A self-hosted AI agent you can talk to via Telegram, Slack, WebChat, or HTTP webhooks. It remembers things, runs scheduled tasks, executes code, searches the web, and can be extended with custom skills and plugins — all driven by a single config file with a built-in web UI for configuration and management.
- Multi-channel — Telegram, Slack (DMs + groups), WebChat, HTTP Webhooks, Email, WhatsApp (native, QR scan)
- Web UI — browser-based chat, visual config editor, memory browser, sessions, cron, skills, vault, log viewer, and WhatsApp pairing
- Onboarding wizard — guided first-run setup via the browser: vault key generation, WebUI password, provider and model selection; no manual config editing required
- Long-term memory — searchable, taggable, pinnable facts that persist across conversations and channels; proactive retrieval with tag-boosted recall against incoming messages; inline editing in the Web UI
- Knowledge documents — long-form markdown documents stored in SQLite (not files); CRUD + full-text search via FTS5; a compact "knowledge map" (tag cloud, type breakdown, doc titles) is injected into every system prompt so the agent always knows what it knows without loading content
- Contact memory — store who people are across channels (name, aliases, notes); senders are recognised automatically across Telegram, WhatsApp, and WebChat
- Calendar awareness — CalDAV events for today and tomorrow are injected into every system prompt so the agent is always aware of the current schedule
- Local document RAG — index local notes, markdown files, and PDFs; agent searches them semantically
- Streaming responses — token-by-token streaming in the web chat interface
- Scheduled tasks — UNIX cron expressions and natural language ("in 2 hours", "next Monday at 9am") with a friendly table UI
- Sub-agents —
agent_runspawns a sub-agent and blocks until it returns (ideal for parallel delegation: multipleagent_runcalls in one response execute concurrently);spawnis the fire-and-forget variant that notifies via the message bus on completion - Parallel tool execution — tools marked
parallel=true(e.g.agent_run) are batched and resolved withPromise.allin the LLM loop; sequential tools flush the batch first - SMTP send —
smtp_sendtool for composing and sending email; supports plain text and HTML, CC/BCC, reply-to, in-reply-to threading, default CC, and email signature; config-level defaults hot-reload without restart - Slack interactive buttons — the
messagetool accepts abuttonsarray that renders as Slack Block Kit actions; clicking a button sends the selected value back to the agent as a new message; agent receives an immediate acknowledgement message while it processes the selection - Skills — extend the agent with Markdown-driven skill modules (shell scripts, Python, etc.); activate/deactivate per skill via UI or agent chat
- MCP client — connect to any Model Context Protocol server (stdio, SSE, or HTTP); auto-detects StreamableHTTP with SSE fallback; vault references in env and headers
- Browser automation — Playwright-based browser control (navigate, click, type, screenshot, evaluate JS, and more); screenshots return the image inline to the LLM so it can see the page; persistent browser sessions save/restore cookies and login state across restarts
- CalDAV calendar — read and write calendar events on any CalDAV server (Nextcloud, Radicale, etc.)
- Dynamic tool registry — tool groups are self-contained providers; enable/disable/reload without restart; MCP tools filtered by relevance to save tokens
- Plugins — load custom tools and channels dynamically at runtime
- Context files — personality, identity, and task files injected into every session;
BOOTSTRAP.mdtriggers a guided self-introduction conversation on first contact - Provider agnostic — Anthropic Claude, OpenAI GPT, Gemini, OpenRouter, any OpenAI-compatible API
- Reasoning models — first-class support for o-series models with adaptive reasoning effort escalation
- Session compaction — automatic summarisation of long conversations to stay within token limits
- Config + channel hot-reload — save config via the Web UI and providers, channels, and tools reload instantly without a restart
- Prompt injection protection — context-aware security manager blocks high-risk tool calls triggered by external content
- Skill integrity signing — SHA-256 manifest ensures skill files are not tampered with before credentials are injected
- Node.js 20+
- pnpm
- An API key for at least one LLM provider (Anthropic, OpenAI, Gemini, or any OpenAI-compatible endpoint)
git clone https://github.com/verox-ai/verox.git
cd verox
./install.shThe script will:
- Install dependencies with pnpm
- Build the server and web UI
- Create an
veroxsymlink in/usr/local/bin(falls back to~/.local/bin)
pnpm install
pnpm run build
pnpm run build:ui
chmod +x dist/index.js
sudo ln -s "$(pwd)/dist/index.js" /usr/local/bin/veroxcd verox
./update.shStops the service (if running), pulls latest code, rebuilds, and restarts.
On first start, Verox creates ~/.verox/ with a default workspace and an example config:
~/.verox/
├── config.json # Main configuration
├── config.example.json # Reference / template
└── workspace/ # Context files, memory, skills, cron jobs
On a fresh install, just start the server — no config needed:
verox start
# → open http://localhost:3000/setupThe terminal will print the exact URL. The browser wizard guides you through:
- Vault key — a random encryption key is generated for you; copy it and set it as
VEROX_VAULT_PASSWORDin your environment or systemd unit, then restart. The wizard detects the key automatically and advances. - WebUI password — enter a password; it is stored in the encrypted vault. No config file editing required.
- Provider & model — choose your LLM provider (Anthropic, OpenAI, Ollama, or any compatible endpoint), select or type a model name, and enter your API key. The key is stored in the vault, not in
config.json. WebChat is enabled automatically.
Once all three steps are complete, the wizard redirects you to the chat interface. On subsequent starts the wizard is skipped entirely.
The Web UI includes:
| Page | Description |
|---|---|
| Chat | Talk to the agent with streaming responses and live tool-call progress |
| Config | Visual schema-driven config editor — all sections and fields rendered automatically from the schema |
| Vault | Browse and edit encrypted credentials |
| Memory | Search, browse, pin, edit (inline), and delete memory entries; knowledge map widget with clickable tag cloud |
| Knowledge | Full CRUD for long-form knowledge documents with FTS search and live markdown preview |
| Sessions | View active sessions and conversation history |
| Cron | Schedule, view, and cancel cron jobs |
| Skills | Browse installed skills and their status |
| Docs | Document store status and indexed file listing |
| Logs | Live log tail with level and text filters |
The config editor is schema-driven — adding a new field to the Zod schema automatically adds it to the UI with the correct input type, label, help text, and sensitive-field masking. No frontend changes required.
Config changes take effect immediately without a restart. The agent watches config.json for changes and hot-reloads all settings — provider credentials, tool configs, CalDAV/browser connections, context window settings, and more. Stateful clients (CalDAV, browser) are updated in-place; providers that become enabled (e.g. caldav.enabled toggled to true) are loaded on the fly.
verox config wizardWalks you through providers, channels, and agent settings with an interactive menu. Passwords are masked, current values are shown inline.
verox config set providers.openai.apiKey sk-...
verox config set agents.defaults.provider openai
verox config show
verox config edit # opens in $EDITORverox startverox service add # user service (no sudo needed)
verox service add --system # system service (requires root)Enables and starts the service immediately. To follow logs:
journalctl --user -u verox -f # user service
journalctl -u verox -f # system serviceRemove the service:
verox service removeThe workspace directory (~/.verox/workspace/ by default) holds all the files the agent reads at startup:
| File | Purpose |
|---|---|
AGENTS.md |
Core behavioural rules and response style |
SOUL.md |
Personality and values |
IDENTITY.md |
Product/persona identity |
USER.md |
Facts about the user — name, preferences, timezone |
TOOLS.md |
Guidance on when and how to use tools |
BOOT.md / BOOTSTRAP.md |
Project or environment context |
HEARTBEAT.md |
Instructions for the periodic heartbeat task |
Edit these files to shape how the agent behaves. Changes take effect on the next conversation turn (no restart required).
The agent maintains long-term memory in a SQLite database (workspace/memory/memory.db). Memories are tagged facts that persist across sessions and channels.
Tags used by convention: preferences, decisions, people, tasks, technical, facts, reminders, pin
The pin tag makes an entry always appear in the system prompt regardless of age. Use it sparingly for critical facts.
Memory is injected into every session automatically using a three-tier strategy:
- Pinned — entries tagged
pinalways appear first - Relevant — entries whose content matches keywords in the incoming message, plus a tag-boost pass that matches existing tags against message words for higher-precision recall (up to 12 entries)
- Recent — entries from the last 7 days not already shown
The system prompt also includes a compact knowledge map: total memory count, memory type distribution, top tags with frequencies, recent tags, and titles of all knowledge documents. This tells the agent the shape of what it knows without loading any content — it can call knowledge_read on demand for the full text.
The agent can search, write, and delete memories and knowledge documents using its built-in tools.
For longer reference material (how-to guides, project context, structured notes), the agent stores knowledge documents in the same SQLite database. Unlike memory entries (short facts), knowledge docs support:
- Full markdown content of any length
- Slug-based addressing (
knowledge_read slug) - Full-text search across title, content, and tags
- CRUD via agent tools or the Web UI knowledge page (with live markdown preview)
When the agent reads external content (email bodies, web pages), the session messages are annotated with the source risk level. The memory extraction pipeline inherits that risk level and stores it alongside each extracted fact.
High-risk memory entries are never injected automatically into the system prompt. They remain searchable and recallable via memory_search — but accessing them raises the security context level, so any subsequent dangerous tool calls (exec, imap_update, etc.) are blocked until the user explicitly confirms.
This prevents an attacker from poisoning the agent's long-term memory via a crafted email and then having that instruction silently appear in every future conversation.
verox memory list
verox memory list --tag preferences
verox memory list --search "dark mode"
verox memory get <id>
verox memory write # interactive
verox memory delete <id>The agent can schedule and manage its own cron jobs using the cron tool. Jobs are persisted in workspace/cron/jobs.json and survive restarts.
"Remind me every morning at 8 AM about my priorities for the day via Telegram"
The agent will call the cron tool with the appropriate schedule and target.
verox cron list
verox cron add
verox cron cancel <id>The heartbeat runs every 30 minutes and sends the agent the contents of HEARTBEAT.md as a prompt. Use it for recurring light tasks — checking emails, sending a daily summary, monitoring a service.
Leave HEARTBEAT.md empty or comment everything out to disable it without touching config.
Skills extend the agent with domain-specific capabilities. A skill is a directory under workspace/skills/{name}/ containing:
workspace/skills/
└── homeassistant/
├── SKILL.md # Description + tool usage guidance (YAML frontmatter)
├── config.json # Skill-local config values
└── config.schema.json # Schema + env export declarations
SKILL.md frontmatter example:
---
description: Control Home Assistant devices and automations
always: false
requires:
binaries: [curl]
env: [HA_URL, HA_TOKEN]
---config.schema.json example:
{
"properties": {
"url": { "type": "string", "envName": "HA_URL" },
"token": { "type": "string", "envName": "HA_TOKEN" }
}
}Fields with envName are injected into the environment of any shell commands the skill runs, so secrets never appear in the global process environment.
Skills marked always: true are loaded into every session automatically.
Before a skill can receive vault credentials and be trusted to produce safe output, its entry-point file must be signed. Signing stores a SHA-256 hash in an encrypted manifest (~/.verox/skill-manifest.enc). The hash is verified immediately before every execution — if the file has been modified since signing, the call is blocked.
# After installing or updating a skill:
export VEROX_VAULT_PASSWORD="your-vault-password"
verox skills sign homeassistant
verox skills verify homeassistant
verox skills list
verox skills unsign homeassistantSecurity implications:
| Skill state | Vault credentials | Output risk |
|---|---|---|
| Signed, hash matches | Injected | As configured |
| Not signed | Not injected | Forced to High |
| Signed, hash mismatch | Not injected | Execution blocked |
An unsigned skill always produces RiskLevel.High output — meaning any tool call the agent makes after running it is subject to the same restrictions as if it had read an email body.
When the agent reads external content — email bodies, web pages, crawled sites — an attacker can embed instructions directed at the agent. Verox counters this with a context risk level that rises as the agent consumes external data, and blocks dangerous tool calls once the context is contaminated.
| Level | Set by | Meaning |
|---|---|---|
None |
User message (reset every turn) | Trusted context — agent is acting on user intent |
Low |
Email metadata, search results, file reads | Some external data seen — low-impact tools still allowed |
High |
Email bodies, web pages, exec output, unsigned skills | Full external content — only safe read operations allowed |
| Tool | Output risk | Max allowed context | Notes |
|---|---|---|---|
exec |
High | None | Only runs from user-initiated context |
spawn |
High | None | Subagent spawning requires user intent |
imap_update |
— | None | Write/delete/move requires user intent |
imap_read |
High | High | Body is attacker-controlled |
imap_mail |
Low | High | Metadata only (uid, subject, from, date) |
web_fetch / web_crawl |
High | High | Full page content |
web_search |
Low | High | Titles and snippets only |
read_file |
Low | High | Local file content |
write_file / edit_file |
— | High | Writing is safe from any context |
http_request |
High | High | External API response is untrusted |
docs_search |
Low | High | Local content, treat chunks as external |
docs_get |
Low | High | Full file content |
When a blocked tool call occurs, the agent receives a [SECURITY_HOLD] message and is instructed to surface the request to the user for confirmation. A new user message resets the context back to None.
"tools": {
"security": {
"imap_read": { "maxRisk": "none" },
"web_search": { "maxRisk": "none", "outputRisk": "none" }
},
"skillSecurity": {
"weathercheck": { "maxRisk": "high", "outputRisk": "low" }
}
}tools.security — overrides for built-in tools. Keys are tool names.
tools.skillSecurity — overrides for individual skills. Only use this for skills that are strictly read-only with no side effects. Never relax skills that control physical devices, send messages, or modify data.
Skill security overrides only apply to signed skills. An unsigned skill always produces
Highoutput risk regardless of config.
Verox includes an encrypted credential vault that keeps sensitive secrets out of config.json and out of reach of the AI agent itself.
The vault stores credentials as a single AES-256-GCM encrypted blob at ~/.verox/vault.enc. The decryption key is derived at runtime from a password supplied as an environment variable — it is never written to disk.
| Key pattern | Effect |
|---|---|
config.<dot.path> |
Overrides a field in config.json at parse time |
skill.<skillname>.<scriptname>.<ENV_VAR> |
Injected into the environment of a matching skill script |
config.json can be committed to version control or shared without exposing any secrets — the real values live only in the encrypted vault.
export VEROX_VAULT_PASSWORD="your-strong-password"
# Store provider keys (replaces plaintext in config.json)
verox vault set config.providers.anthropic.apiKey sk-ant-...
verox vault set config.providers.openai.apiKey sk-...
verox vault set config.channels.telegram.token 1234567:abc...
# Store skill credentials
verox vault set skill.homeassistant.index.HA_TOKEN your-ha-token
verox vault set skill.homeassistant.index.HA_URL http://homeassistant.local:8123verox vault set <key> <value> Store a credential
verox vault get <key> Print a stored value
verox vault list List all stored keys
verox vault delete <key> Remove a credential
| Threat | Mitigation |
|---|---|
Agent reads config.json via read_file |
API keys are not in config.json — only in the encrypted vault |
| Agent runs a malicious script that reads the vault file | Vault is AES-256-GCM encrypted; useless without the password |
Agent exfiltrates VEROX_VAULT_PASSWORD via exec |
Password is stripped from all child process environments |
| Agent writes a malicious script to steal injected credentials | Unsigned/unreviewed scripts never receive vault credentials |
| Prompt injection modifies a skill file to exfiltrate credentials | SHA-256 hash checked immediately before exec — tampered files are blocked |
Prompt injection via email triggers exec or physical device control |
SecurityManager blocks high-risk tools when context is contaminated |
Wraps each exec'd command in a new PID + user namespace using unshare. Inside the namespace the child gets its own /proc mount and cannot see any parent processes.
"tools": { "exec": { "usePidNamespace": true } }Requirement: Linux with unprivileged user namespaces enabled (default on Ubuntu 16.04+, Debian 10+, Fedora, Arch).
sudo useradd --system --no-create-home --shell /usr/sbin/nologin verox-exec
sudo visudo -f /etc/sudoers.d/verox
# Add: verox ALL=(verox-exec) NOPASSWD: /bin/sh"tools": { "exec": { "runAs": "verox-exec" } }If both usePidNamespace and runAs are set, usePidNamespace takes precedence.
Index local notes, markdown files, and PDFs so the agent can search them semantically.
Indexing (docs_index): Walks configured paths, hashes each file (skips unchanged), extracts text, splits into overlapping chunks, embeds via the configured embedding model, and stores float32 vectors in SQLite.
Searching (docs_search): Embeds the query with the same model, computes cosine similarity against all stored chunk vectors in-process, returns top-N chunks with source path and score.
"tools": {
"docs": {
"enabled": true,
"paths": [
{ "name": "Personal Notes", "path": "/home/user/notes" },
{ "name": "Paperless", "path": "/mnt/paperless/data" }
],
"embeddingModel": "text-embedding-3-small"
}
}If your chat provider doesn't support /embeddings (e.g. OpenRouter), point the docs tool at a separate provider via embeddingApiBase and embeddingApiKey.
verox docs index # Index all configured paths (skips unchanged)
verox docs index --force # Re-index everything
verox docs list # List all indexed filesThe http_request tool lets the agent call external HTTP APIs:
"tools": {
"web": {
"http": {
"allowedHosts": ["api.example.com"] // Empty = allow all hosts
}
}
}Supports GET, POST, PUT, PATCH, DELETE, HEAD with arbitrary headers and request bodies. Response bodies are truncated at the configured maxResponseBytes limit; JSON is pretty-printed automatically. Output risk: High.
Verox can connect to any MCP server and expose its tools to the agent as native tools. Connections are established at startup before the agent begins processing.
"mcp": {
"servers": {
"filesystem": {
"transport": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/home/user"],
"env": {
"SOME_KEY": "vault:config.mcp.servers.filesystem.somekey"
}
},
"homeassistant": {
"transport": "http",
"url": "http://homeassistant.local:8123/mcp",
"headers": {
"Authorization": "Bearer $vault:config.mcp.servers.homeassistant.token"
},
"alwaysInclude": false
}
}
}| Transport | Field | Description |
|---|---|---|
stdio |
command, args, env |
Launches a local process (e.g. npx, uvx, python) |
sse |
url, headers |
Server-Sent Events (legacy MCP) |
http |
url, headers |
Streamable HTTP (current MCP spec) |
Two syntaxes are supported for injecting secrets without storing them in config.json:
| Syntax | Effect |
|---|---|
vault:<key> |
Entire value replaced by vault entry; variable omitted if key not found |
$vault:<key> |
Inline substitution within a larger string (e.g. Bearer $vault:mykey) |
# Store secrets
verox vault set config.mcp.servers.homeassistant.token "Bearer eyJhb..."MCP servers can expose many tools that are irrelevant to most messages. By default, MCP tools are contextual — they are only sent to the LLM when the user message contains keywords matching their name or description. This keeps the token count low for unrelated requests.
When a needed tool isn't matched by keywords, the LLM can call the always-available tool_search meta-tool to discover and activate it on demand:
"I need to control the lights" → LLM calls
tool_search("control smart home lights")→ HA tools activated for this turn
Set alwaysInclude: true on a server to bypass filtering and always include its tools (useful for small servers whose tools are frequently needed regardless of context).
The Web UI config page shows a live status badge on each MCP server card:
- Green dot + tool count — connected and tools registered
- Red dot + "error" — connection failed (hover for the error message)
Status is also available via GET /api/mcp/status.
Verox includes a Playwright-based browser that the agent can control to interact with web pages programmatically.
Install the browser binary (one-time):
npx playwright install chromiumEnable in config:
"tools": {
"browser": {
"enabled": true,
"headless": true,
"timeout": 30000,
"allowedDomains": [] // Empty = allow all domains
}
}| Tool | Description |
|---|---|
browser_navigate |
Navigate to a URL |
browser_screenshot |
Take a screenshot — returns the image inline to the LLM so it can see the page |
browser_get_content |
Get the page's text content or HTML |
browser_click |
Click an element by CSS selector |
browser_type |
Type text into an input |
browser_select |
Select an option in a <select> element |
browser_wait |
Wait for an element to appear |
browser_evaluate |
Execute JavaScript in the page context |
browser_close |
Close the browser |
browser_session_save |
Save browser state (cookies, localStorage) to a named session file |
browser_session_load |
Restore a previously saved session (survives restarts) |
browser_session_clear |
Delete a saved session file |
All browser tools have maxRisk = None (require a clean context to run). browser_get_content, browser_evaluate, and browser_screenshot produce outputRisk = High since they return page-controlled content.
Browser sessions persist login state across agent restarts. Save a session after logging in to a site; load it next time to resume without re-authenticating.
Connect to any CalDAV server (Nextcloud, Radicale, Baikal, iCloud, etc.) to read and manage calendar events.
"tools": {
"caldav": {
"enabled": true,
"serverUrl": "https://nextcloud.example.com/remote.php/dav",
"username": "alice",
"password": "", // Leave blank and store in vault instead
"defaultCalendar": "Personal" // Partial match; uses first calendar if blank
}
}Store the password securely:
verox vault set config.tools.caldav.password "app-specific-password"| Tool | Description |
|---|---|
calendar_list |
List all available calendars |
calendar_get_events |
Get events for a calendar (with optional date range) |
calendar_create_event |
Create a new event |
calendar_update_event |
Update an existing event by UID |
calendar_delete_event |
Delete an event by UID |
Plugins can add custom tools and channels at runtime:
{
"plugins": {
"enabled": true,
"load": { "paths": ["/path/to/my-plugin.js"] }
}
}A plugin exports a default object with optional tools and channels factories. Plugin config schemas are automatically merged into the Web UI config editor.
verox start Start the agent
verox config wizard Interactive configuration wizard
verox config show Print full config as JSON
verox config get <key> Get a value (dot notation)
verox config set [key] [value] Set a value (interactive if omitted)
verox config edit Open config in $EDITOR
verox memory list [-t tag] [-s query]
verox memory get <id>
verox memory write
verox memory delete <id>
verox cron list
verox cron add
verox cron cancel <id>
verox service add [--system]
verox service remove [--system]
verox vault set <key> <value>
verox vault get <key>
verox vault list
verox vault delete <key>
verox skills sign <skillname>
verox skills verify <skillname>
verox skills list
verox skills unsign <skillname>
verox docs index [path] [--force]
verox docs list
| Variable | Description |
|---|---|
VEROX_HOME |
Override the data directory (default: ~/.verox) |
VEROX_VAULT_PASSWORD |
Password for the encrypted credential vault. Required for vault and skill-signing features. |
Verox can subscribe to RSS/Atom feeds and surface new items automatically.
// config.json — no dedicated section needed; manage via agent tools or the Web UI (/settings/rss)| Tool | Description |
|---|---|
rss_subscribe |
Subscribe to a feed URL with an optional label and check interval |
rss_unsubscribe |
Remove a subscription by id |
rss_list |
List all active subscriptions and their last-check timestamps |
rss_fetch |
Fetch and return the latest items from a subscription |
rss_check |
Manually trigger a check for subscriptions marked manual: true |
Set manual: true on a subscription to skip the automatic polling schedule and only fetch on demand via rss_check.
Workflows let the agent plan and execute multi-step tasks that span multiple turns.
| Tool | Description |
|---|---|
workflow_plan |
Draft a step-by-step plan for a goal |
workflow_save |
Persist a plan to disk so it survives restarts |
workflow_activate |
Start executing a saved workflow |
workflow_cancel |
Cancel an in-progress workflow |
workflow_list |
List all saved and active workflows |
In addition to individual memory entries, Verox maintains a layered context injection system:
| Level | What | When injected |
|---|---|---|
| Atlas | _memory_atlas — compact overview of all topics, type breakdown, and recent focus |
Every turn |
| Topic summaries | _topic_summary_<tag> — up to 15 recent entries for a tag |
When the current message mentions that topic |
| Relevant entries | FTS5-ranked entries matching the current message keywords | Every turn (up to 22) |
| Recent entries | Most recently created entries | Every turn |
The atlas and topic summaries are regenerated nightly by the reflection cron job (midnight). Use knowledge_read _memory_atlas to inspect the current atlas, or knowledge_read _topic_summary_<tag> for a specific topic.
| Tool | Description |
|---|---|
memory_write |
Save a fact to long-term memory |
memory_search |
Search memory by text and/or tags |
memory_list_tags |
List all tags in use |
memory_delete |
Delete a memory entry |
knowledge_write |
Create or replace a knowledge document by slug |
knowledge_read |
Load the full content of a knowledge document |
knowledge_search |
Full-text search across knowledge document title, content, and tags |
knowledge_list |
List all knowledge document slugs and titles |
knowledge_delete |
Delete a knowledge document |
cron |
Schedule, cancel, or list cron jobs |
message |
Send a message to a channel with optional file attachments and interactive buttons (Slack Block Kit) |
sessions_list |
List active sessions |
sessions_history |
Get conversation history for a session |
sessions_send |
Send a message to another session |
usage_stats |
Show token usage statistics |
provider_list |
List configured LLM providers |
provider_switch |
Switch the active provider |
security_check |
Check current security context level |
tool_search |
Discover and activate contextual tools (e.g. MCP tools) not currently visible |
| Tool | Description |
|---|---|
exec |
Run a shell command |
agent_run |
Delegate a task to a sub-agent and wait for the result; multiple calls in one response run in parallel |
spawn |
Spawn a background sub-agent (fire-and-forget); result posted back via the message bus |
subagents |
List, steer, or kill background sub-agents |
read_file |
Read a file |
write_file |
Write a file |
edit_file |
Edit a file by string replacement |
list_dir |
List directory contents |
| Tool | Description |
|---|---|
web_search |
Search the web |
web_fetch |
Fetch a web page |
web_crawl |
Crawl a URL via a configured crawl service |
http_request |
Make an HTTP request to an external API |
| Tool | Description |
|---|---|
smtp_send |
Send an email; supports plain text and HTML, CC/BCC, reply-to override, in-reply-to threading; config-level defaults for reply-to, default CC, and signature are applied automatically |
"tools": {
"smtp": {
"enabled": true,
"host": "smtp.example.com",
"port": 587,
"user": "agent@example.com",
"password": "", // Store in vault: config.tools.smtp.password
"from": "Agent <agent@example.com>",
"replyTo": "you@example.com", // Replies go to you, not the agent mailbox
"defaultCC": "", // Always CC'd on every outgoing email
"signature": "" // Appended to every email body
}
}| Tool | Description |
|---|---|
imap_mail |
List/search emails — metadata only (uid, subject, from, date) |
imap_read |
Read the full body of an email by uid |
imap_update |
Mutate email state: mark_seen, mark_unseen, move, delete |
imap_draft |
Compose and send an email via SMTP |
| Tool | Description |
|---|---|
docs_index |
Index local documents for semantic search |
docs_search |
Semantic search over indexed local documents |
docs_list |
List all indexed documents |
docs_get |
Read the full text of an indexed document |
| Tool | Description |
|---|---|
calendar_list |
List available calendars |
calendar_get_events |
Get events for a calendar with optional date range |
calendar_create_event |
Create a new calendar event |
calendar_update_event |
Update an existing event by UID |
calendar_delete_event |
Delete an event by UID |
| Tool | Description |
|---|---|
browser_navigate |
Navigate to a URL |
browser_screenshot |
Take a screenshot — image returned inline to the LLM |
browser_get_content |
Get the page's text content or HTML |
browser_click |
Click an element by CSS selector |
browser_type |
Type text into an input field |
browser_select |
Select an option in a <select> element |
browser_wait |
Wait for an element to appear |
browser_evaluate |
Execute JavaScript in the page context |
browser_close |
Close the browser |
browser_session_save |
Save cookies and login state to a named session file |
browser_session_load |
Restore a previously saved session |
browser_session_clear |
Delete a saved session file |
MCP tools are registered at startup with names in the form mcp__{serverName}__{toolName}. They are contextual by default — only included in requests when the message contains matching keywords, or when activated via tool_search. Set alwaysInclude: true on the server to always include its tools.
MIT
{ "agents": { "defaults": { "workspace": "~/.verox/workspace", "provider": "openai", // Preferred provider name "maxTokens": 8192, "temperature": 0.7, "maxToolIterations": 20 }, "context": { "memory": { "enabled": true, "maxChars": 8000 // Characters of memory injected per turn } }, "compaction": { "enabled": true, "thresholdTokens": 6000, "keepRecentMessages": 10 }, "memoryExtraction": { "staleHours": 4, // Extract from sessions idle longer than this "minMessages": 3 }, "memoryPruning": { "enabled": true, "maxAgeDays": 90, "minConfidence": 0.3, "maxEntries": 1000 } }, "providers": { "openai": { "apiKey": "sk-...", "apiBase": "https://api.openai.com/v1", "model": "gpt-4o", "utilityModel": null, // Lighter model for compaction/extraction "wireApi": "auto", // auto | chat | responses "promptCaching": false, "reasoningEffort": null, // low | medium | high (o-series only) "adaptiveReasoning": false // Escalate effort as iterations increase }, "anthropic": { "apiKey": "sk-ant-...", "apiBase": "https://api.anthropic.com/v1", "model": "claude-opus-4-6", "promptCaching": true // Anthropic cache_control for system prompt }, "gemini": { "apiKey": "...", "apiBase": "https://generativelanguage.googleapis.com/v1beta/openai", "model": "gemini-2.0-flash" }, "openrouter": { "apiKey": "...", "apiBase": "https://openrouter.ai/api/v1", "model": "anthropic/claude-opus-4-6" } }, "channels": { "webchat": { "enabled": true, "port": 3000, "host": "0.0.0.0", "uiToken": "" // Auto-generated and stored in vault if blank }, "telegram": { "enabled": false, "token": "...", "policy": "restricted", // none | restricted "allowFrom": ["123456789"] }, "slack": { "enabled": false, "botToken": "xoxb-...", "appToken": "xapp-...", "mode": "socket", // socket | http "groupPolicy": "mention" // none | mention | restricted }, "email": { "enabled": false, "imapHost": "", "imapPort": 993, "imapUsername": "", "imapPassword": "", "smtpHost": "", "smtpPort": 587, "smtpUsername": "", "smtpPassword": "", "fromAddress": "", "pollIntervalSeconds": 30 }, "webhook": { "enabled": false, "port": 3001, "path": "/webhook", "jwtSecret": "..." } }, "tools": { "web": { "search": { "apiKey": "...", // Brave Search / compatible API key "strUrl": "", // Search provider URL "maxResults": 5 }, "crawl": "", // Crawl service URL (e.g. Jina) "http": { "allowedHosts": [], // Empty = allow all hosts "maxResponseBytes": 100000 } }, "exec": { "timeout": 60, "usePidNamespace": false, // Linux: isolate /proc (see security section) "runAs": null // OS user to run commands as }, "imap": { "host": "", "port": 993, "user": "", "password": "", "tls": true }, "docs": { "enabled": false, "paths": [ { "name": "Notes", "path": "/home/user/notes" } ], "embeddingModel": "text-embedding-3-small", "embeddingDims": 1536, "chunkSize": 800, "chunkOverlap": 100, "maxResults": 5, // Optional: separate embedding provider (e.g. when using OpenRouter for chat) "embeddingApiBase": "https://api.openai.com/v1", "embeddingApiKey": "sk-..." }, "restrictFilesToWorkspace": false, "restrictExecToWorkspace": false, "caldav": { "enabled": false, "serverUrl": "https://nextcloud.example.com/remote.php/dav", "username": "", "password": "", // Store in vault: config.tools.caldav.password "defaultCalendar": "" }, "browser": { "enabled": false, "headless": true, "timeout": 30000, "allowedDomains": [] // Empty = allow all domains } }, "mcp": { "servers": { "myserver": { "transport": "stdio", // stdio | sse | http "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"], "env": {}, "url": "", "headers": {}, "alwaysInclude": false // true = always send tools to LLM (bypasses keyword filter) } } } }