BoteX
BoteX is an MCP server for orchestrating guarded autonomous code-editing subagents and managing workspace memory/diagnostics.
Run synchronous coding tasks via
run_subagentor detached tasks viastart_task, then poll withget_task_status.Control execution with modes (
readonly/edit/destructive/full), budgets, turn/time/token limits, approvals, workspace scoping, verification commands, and ZDR/net/exec/destructive permissions.Inspect files efficiently with
get_outline, and fetch public URLs viafetch_url.Discover cost/capability-appropriate models with
recommend_models.Use the Memory Vault: save, search, read, delete, patch sections, list backlinks, audit graph health, initialize Obsidian vault config, and read scratchpad logs.
Check analytics/costs (
get_stats), environment readiness (check_health), and prune snapshots (clean_snapshots).
Allows using NVIDIA as a model provider for autonomous code-execution tasks, with configurable profiles and model fallbacks.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@BoteX Add email validation to auth/validators.py and cover it with tests"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
BoteX: Execution Harness for AI Coding Agents
Giving an LLM direct, unrestricted access to your repository usually ends the same way: it hallucinates line numbers, corrupts indentation, writes broken syntax, eats your token budget reading thousands of irrelevant lines, or gets stuck in an infinite fix-break loop.
BoteX is a guardrail harness designed specifically for autonomous code-editing agents. It sits between an MCP client (such as Devin, Antigravity, Claude Desktop, or Cursor) and your codebase, enforcing deterministic safeguards before any code ever touches your disk.
Why BoteX?
Instead of trusting the model to behave, BoteX wraps every action in safety gates:
Outline-first inspection: Agents inspect symbol skeletons (
get_outline) before asking for specific line ranges. This prevents dumping massive files into context and slashes token waste.Prompt Injection & Untrusted Data Isolation (OWASP LLM01: Prompt Injection): External content retrieved by tools (file contents, web pages, memory notes) is automatically wrapped in XML-like untrusted data boundary tags (
<untrusted_file_content>,<untrusted_web_content>,<untrusted_memory_content>). System prompt rules instruct the LLM to treat bounded content strictly as data, significantly reducing prompt injection risks.Sensitive Information Disclosure & Secret Guardrails (OWASP LLM02: Sensitive Information Disclosure): Prevents accidental leaks by blocking access to environment files (
.env*), SSH keys, credentials, and local configurations (botex.config.local.json). Automatically redacts API keys, Bearer tokens, private keys, and provider secrets in tool outputs and logs.Read-before-write gate: Models cannot patch a file they haven't inspected in the current session. No blind edits, no guessing.
Pre-write syntax validation: Code modifications are validated in memory (e.g.
ast.parsefor Python) before saving. If the patch breaks syntax, it gets rejected on the spot.Multi-tier fuzzy patching: Patches are whitespace- and newline-resilient (CRLF/LF agnostic with indentation detection), so minor formatting mismatches don't break execution.
Unbounded Consumption Protection (OWASP LLM06: Unbounded Consumption): Prevents "Denial of Wallet" and infinite loop resource exhaustion. BoteX evaluates USD spend dynamically mid-loop to enforce the budget cap instantly, and aborts with an automatic rollback if the agent falls into a mutation streak or stagnation loop.
Misinformation Protection (OWASP LLM07: Misinformation): Generated code undergoes rigorous in-memory AST and syntax validation (including
rufffor Python andbash -nfor shell scripts) to reject hallucinated or invalid code before touching disk. Post-writeverify_commandacts as a mandatory final test gate.Improper Output Handling (OWASP LLM10: Improper Output Handling): Strict Read-Before-Write gates ensure no blind writes occur, and every touched file is backed by a pre-mutation snapshot. If an agent hits an error, the automatic snapshot rollback reverts the workspace cleanly.
Hard budget & pricing caps: Pre-flight checks verify model pricing against live provider catalogs. If a task exceeds its budget or a model is overpriced, BoteX aborts before spending a cent.
Strict privacy & Zero Data Retention (ZDR): Enforces
provider.data_collection: denyon OpenRouter calls, blocks.env/secrets, masks API keys in logs, and prevents path traversal attacks. Free (:free) models that cannot guarantee ZDR are rejected locally. Opt out explicitly per run (allow_non_zdr) or via theopenrouter-freeprovider preset.Proactive Rate Limiting & Cooldown Tracking: Token-bucket rate limiter tracks RPM and TPM limits per provider with burst buffers and debt queues. When providers return rate-limit headers or 429 status codes, BoteX enters a cooldown window instead of repeatedly burning retries.
In-Flight State Checkpointing & Provider Fallbacks: Failed model runs take a snapshot of planned steps, observations, and read files before rolling back workspace changes. The next model or fallback provider receives this context directly, avoiding redundant exploration.
Enhanced Permission Controls (OWASP LLM03: Excessive Agency): BoteX protects against Excessive Agency via a centralized Agency Middleware. Tools are strictly defined with Risk Levels (LOW, MEDIUM, HIGH) and required scopes. High-risk destructive actions automatically require explicit interactive operator approval (or pre-authorized task scopes in headless mode), limiting the potential damage of prompt injections or hallucinations.
Related MCP server: dsh-codex-bridge
Quickstart
1. Installation
Requires Python 3.10+:
pip install -r requirements.txt(Optional: install globally via pip install . to get the botex CLI command).
2. Add your API key
BoteX handles provider keys internally, so calling MCP clients don't need to pass credentials on every request. Create a .env file next to server.py:
OPENROUTER_API_KEY=sk-or-v1-...
# GEMINI_API_KEY=AIza... # only for provider "google" (GOOGLE_API_KEY works as fallback)Key lookup order: OPENROUTER_API_KEY env var → local .env → custom paths.env_file → botex.config.local.json (gitignored). For provider google, the key resolves via GEMINI_API_KEY → GOOGLE_API_KEY → secrets.google_api_key in config.
3. Connect to your MCP client
You can run BoteX as a local stdio process or as a remote service over SSE.
Option A: Local Process (stdio)
Register BoteX using the included zero-install launchers (botex.cmd on Windows, botex.sh on Linux/macOS) or directly with Python:
{
"mcpServers": {
"botex": {
"command": "C:/path/to/harness/botex.cmd"
}
}
}Option B: Remote MCP via SSE (Cloud or VPS)
Start the gateway with botex cloud and connect via Server-Sent Events (SSE):
{
"mcpServers": {
"botex-cloud": {
"url": "http://127.0.0.1:8000/mcp/sse",
"headers": {
"Authorization": "Bearer <your_token>"
}
}
}
}How It Works
Every delegated task goes through an explicit contract-driven lifecycle:
Delegated Task
│
▼
[Pre-flight check] ──► Validate budget, model capabilities & price cap
│
▼
[Tool Loop] ──► Symbol outline ─► Target read ─► In-memory patch ─► Syntax check
│
├─► Success ──► Verify contract (file exists, syntax valid, verify_command passed) ─► DONE
│
└─► Failure ──► Rollback snapshots ─► Try next candidate (model_fallbacks) or abortA task returns ok: true only when its completion is verified on disk, not just because an LLM said "I'm done". For background tasks (start_task / get_task_status), status reports the execution lifecycle (QUEUED, RUNNING, DONE, FAILED, CANCELLED); lifecycle DONE means the run finished, not success. Success requires result_data.ok == true and result_data.status == "DONE".
MCP Tools Reference
BoteX exposes a focused set of MCP tools:
Task Execution
run_subagent(task, ...): Runs a full coding task synchronously and blocks until finished. Returns both human-readable text and detailed structured metadata.start_task(task, ...): Launches a task asynchronously in the background and returns atask_id.get_task_status(task_id): Polls progress, logs, and results for a background task.
Two-Tier Memory Vault
save_memory(title, content, workspace_dir, kind, tags, memory_id, scope): Saves persistent notes, decisions, handoffs, or lessons. Scope can be"local"(<workspace_dir>/.botex/memory/) or"global"(~/.botex/memory/).read_memory(memory_id, workspace_dir, scope)/search_memory(workspace_dir, query, tag, kind, scope): Retrieves saved memory across local or global storage (scope="all"searches both).patch_memory_section(memory_id, section, new_content, workspace_dir, scope, append): Replaces or appends one Markdown section in a memory note without touching frontmatter, other sections, or the Timeline trail.delete_memory(memory_id, workspace_dir, scope): Deletes a specific memory note from local or global storage.get_backlinks(memory_id, workspace_dir, scope): Lists memories that link to the given note through[[wikilinks]].find_graph_health(workspace_dir, scope): Audits the vault's wikilink graph — reports broken links, orphan notes, and cycles.init_obsidian_vault(workspace_dir, scope, override_existing, export_index): Writes.obsidian/config (per-kind graph colors) and optionally regenerates_GRAPH_INDEX.md.read_scratchpad(memory_id, workspace_dir): Reads an execution or terminal log offloaded to.botex/scratchpad/<memory_id>.log.
Diagnostics & Utility
get_outline(path, workspace_dir): Returns a high-level symbol outline of a file without reading all lines.get_stats(period): Generates token usage and cost reports from the local analytics ledger.check_health(): Checks readiness of providers, models, keys, and budget limits.clean_snapshots(max_age_days, max_total_mb): Prunes old workspace backup snapshots.recommend_models(task_type, limit, include_free, provider, profile, tier): Queries/api/v1/modelswith authenticated headers, classifies models intohigh/standard/budgettiers, filters for tool-calling support (require_tools=true) and interactive endpoints (excluding:batch), and ranks models by task aptitude and token cost.include_free=trueadmits:freevariants.fetch_url(url, max_bytes): Safe, caller-side URL fetching with strict host and size filters.
Task Delegation & Parameters
run_subagent and start_task expose the exact same caller parameters, including approval_policy. Example payload:
{
"task": "Add email validation to auth/validators.py and cover it with unit tests",
"files": ["auth/validators.py"],
"workspace_dir": "./my-project",
"profile": "coding"
}Key Parameters
Parameter | Default | Description |
| (required) | Clear description of what needs to be implemented or fixed. |
|
| List of primary target files to nudge the agent toward (target hints, not a security allowlist; |
|
| Root directory the agent is restricted to. Empty = |
|
| API provider from |
|
| Explicit provider model ID; overrides |
|
| Model profile from |
|
| Provider API key per-request (keep empty in examples; do not pass secrets in task or memory). |
|
| Capability preset: |
|
| Specialized workflow persona ( |
|
| Max tool-loop iterations ( |
|
| Per-turn completion cap ( |
|
| Total wall-clock limit in seconds ( |
|
| Hard spend limit for this task ( |
|
| Explicit opt-in for |
|
| Explicit opt-in for |
|
| Explicit opt-in for web access via |
|
| Per-run host authorization for |
|
| Per-run URL authorization; a trailing |
|
| Per-run consent to relax the ZDR gate; required for |
|
| File-output contract: enforce that this exact file must be written and non-empty for |
|
| Human-in-the-Loop policy: |
|
| Verification command (e.g. |
Recipes & System Prompts
BoteX builds the API System Prompt dynamically for each run. It fuses a hardcoded operational core (tool rules, syntax validation checks, output formats) with an optional Recipe (a markdown file).
This means that providing a --recipe <name> (or the "recipe": "<name>" JSON parameter) acts as an injection mechanism for your custom System Prompts, giving the agent specialized personas or specific constraints.
Recipes live in the botex/recipes/ directory.
Examples of custom System Prompts for Modding and Analysis
If you are using BoteX as an MCP Server to analyze game mods or reverse-engineer engine behavior, you can create custom recipes like botex/recipes/ue4.md or botex/recipes/lua_audit.md.
Unreal Engine 4 Modding (
--recipe ue4)You are an expert C++ and UE4 Blueprint reverse engineer. Your primary goal is to identify memory leaks in object instantiation and unsafe cast operations. Always prioritize stability over performance optimizations. Adhere strictly to Epic Games naming conventions.Security Audit (
--recipe lua_audit)You are a strict security auditor analyzing game mods. Review this Lua codebase for potential sandbox escapes, arbitrary file read/write vulnerabilities, and networking exploits. Do not attempt to fix logic bugs; focus only on security vulnerabilities.Code Refactoring & Optimization (
--recipe optimize)You are an optimization expert. The target codebase runs in a heavily restricted environment. Identify inefficient loops, excessive global variable usage, and unnecessary memory allocations. Suggest changes using only standard libraries.
When provided, BoteX automatically appends your recipe to the system instructions before starting the LLM loop.
Safety & Capability Modes
Permissions follow the principle of least privilege. Modes are presets over core capabilities:
Mode | Allowed Operations | Typical Use Case |
| Outline inspection, ranged file reads, memory search. | Architecture reviews, exploratory passes. |
| Read tools + | Standard feature work and bug fixing. |
| Edit tools + | Refactoring, renaming, file reorganizations. |
| Destructive tools + gated | Full autonomous loop (edit → test → fix). |
readonly and chat are hard read-only modes: no local writes, deletions, moves, or command execution. Capability flags cannot widen readonly to write or exec; allow_net adds only read-only network access (read_url). Chat is a separate CLI/REST interface (botex chat, /api/chat), not the normal task delegation API.
Network access (allow_net) is never enabled by default in any preset. It must be explicitly enabled per request or configured via net.allowed_hosts.
Command Execution (run_command) Safety
BoteX is not a full OS sandbox. When allow_exec is granted, processes run under the operator's account. However, BoteX guards execution with multiple layers:
Disabled by default: Requires
exec.enabled: truein configuration.Binary allowlist: Only pre-approved executables (
pytest,python,ruff,git, etc.) can be called.Deny rules: Blocks dangerous arguments (
python -c,git push,rm, shell piping, network downloads).Isolated environment: Executes directly (
shell=False), workspace set as cwd, secret environment variables stripped, and execution timeouts strictly enforced.
Human-in-the-Loop (HITL) Approvals
BoteX integrates an interactive approval manager for high-risk operations. Configure the policy in botex.config.json under approval.policy:
NONE: Auto-approves operations permitted by the capability mode.HIGH_RISK(default): Blocks destructive actions (delete_file,move_file) and shell execution (run_command) until an operator approves.MUTATIONS: Requires operator approval for any file modifications (create_file,apply_patch).ALL_RISKY: Intercepts all mutating tools and system execution commands.
In REPL mode, BoteX prompts for interactive confirmation. In Cloud Gateway mode, actions enter a pending approval queue and can be approved or rejected via REST API (POST /api/approvals/{id}/decide).
Model Fallbacks & OpenRouter Live Routing
If a model refuses a task, burns its token limit without output, or hits provider rate limits, BoteX falls back to alternative models defined in botex.config.json:
"model_fallbacks": {
"default": ["anthropic/claude-sonnet-4", "qwen/qwen3-coder", "deepseek/deepseek-v3.2"],
"auto-beta": ["anthropic/claude-sonnet-4", "qwen/qwen3-coder", "deepseek/deepseek-v3.2"],
"coding": ["anthropic/claude-sonnet-4", "qwen/qwen3-coder", "deepseek/deepseek-v3.2"],
"review": ["openai/gpt-5.4", "google/gemini-2.5-pro", "deepseek/deepseek-r1"],
"fast": ["qwen/qwen3-coder-flash", "openai/gpt-4o-mini", "deepseek/deepseek-v3.2"]
}BoteX uses two complementary failover layers:
In-Payload OpenRouter Failovers (
extra_body.models): Before sending the first turn to OpenRouter, BoteX runs each fallback candidate through all five safety gates (Denylist,Decisions,ZDR,Price,Tools) and passes up to three validated slugs inextra_body["models"]. If the primary endpoint is overloaded on the initial request, OpenRouter switches to the next validated model on the wire without an extra client round-trip. Meta-routers (openrouter/auto,openrouter/pareto-code,openrouter/free) are excluded frommodels: [...], and once a run modifies any file (files_touched) or executes a command (exec_ran), BoteX stripsmodelsfrom subsequent turns so a different model never takes over a mutated workspace mid-task.Engine-Level Rollback & Retry: If an attempt fails mid-run, BoteX verifies that all partial file changes from the failed attempt were rolled back before starting the next candidate model. A fallback model never inherits a dirty workspace.
Before a candidate can fail at all, a shared retry layer (botex/retry.py, configured per provider via providers.<name>.retry) waits out unbilled transient rejections: HTTP 429 and connection errors (Google additionally retries 503 "overloaded"), honoring server wait hints (Retry-After header, retryDelay/quotaResetDelay body fields). Timeouts and other 5xx are never retried — the request may already have executed, so a retry could double-bill it — and daily-quota errors skip the wait entirely so the run falls back immediately. While the layer is enabled, SDK-internal retries are disabled (max_retries=0) so exactly one layer owns the backoff policy; setting "retry": false on a provider hands control back to the SDK. Config keys: enabled (default true), max_waits (2), max_wait_s (60.0), base_delay_s (1.0), jitter_s (1.5). A persistent 429 surfaces as failure_kind: "provider_rate_limited", which is eligible for the model_fallbacks chain.
For OpenRouter runs, BoteX also sets extra_body.provider (data_collection: "deny" when ZDR is active, require_parameters: true when tools or response_format are present, allow_fallbacks: true, and sort: "throughput"), automatically stripping reasoning parameters for non-reasoning model slugs so require_parameters: true never triggers HTTP 404 rejections. On DONE, BoteX queries GET /api/v1/generation?id=... in parallel (with a short 404 retry) to record official billing (total_cost), queue latency (queue_time_ms), inference time (generation_time_ms), and prompt cache read/write tokens in .agent_analytics.json and .botex/memory/ task receipts.
Free Models (Non-ZDR Opt-in)
ZDR is on by default and :free slugs are rejected pre-flight with ZDR_VIOLATION. Operators without a paid subscription (or anyone who accepts that free endpoints may log/train on prompts) can opt in two ways; both leave an audit trail (zdr_enforced: false in the result and a stderr warning):
# Persistent: switch to the bundled free-tier provider preset
# (all profiles resolve to tool-capable :free models)
botex config provider openrouter-free # or BOTEX_PROVIDER=openrouter-free
# or relax ZDR on the current provider (keeps paid models, widens routing)
botex config zdr off # 'on' restores enforcement
# Per-run only, no config change:
botex run "task" --provider openrouter-free
botex run "task" --model qwen/qwen3.8-27b:free --allow-non-zdr{"task": "...", "provider": "openrouter-free"}
{"task": "...", "model": "qwen/qwen3.8-27b:free", "allow_non_zdr": true}:free variants also require the OpenRouter account-level free-model opt-in (privacy settings); without it requests surface as provider_policy_denied. Free models carry per-day rate limits. The model_fallbacks chains in the preset stay entirely on :free slugs.
Configuration
Settings are resolved hierarchically (lowest to highest priority):
botex.config.json: committed defaults (provider profiles, engine limits, security lists).botex.config.local.json: machine-local overrides (gitignored; place custom keys or limits here).BOTEX_*environment variables.
Config files are re-read automatically when they change (file mtime check on every access), so edits to botex.config.local.json - manual or via botex config ... - take effect on the next call, including in a running MCP server; no restart is needed. Environment variables are read from the server process environment, so changing them requires a restart.
Example botex.config.local.json:
{
"engine": {
"budget_limit_usd": 1.0,
"max_turns": 20,
"default_workspace": "C:/projects/my-project"
},
"pricing": {
"max_input_per_mtok": 3.0,
"max_output_per_mtok": 6.0
}
}Standalone CLI & REPL
BoteX can be run directly from your terminal without any MCP client:
Interactive REPL
botex repl -w ./my-project --profile codingPrompts for [y/N] confirmation whenever the agent wants to delete or move files.
The startup banner shows the resolved absolute workspace and where it came from (explicit, default_workspace or cwd), and warns when it is the BoteX repository itself. Inside the REPL, workspace (or cd) prints the current workspace, and workspace <DIR> / cd <DIR> switches the target project for the rest of the session (relative paths are resolved against the current workspace; the directory must exist).
Set a persistent default so that running botex without -w never targets the harness itself:
botex config workspace C:/projects/my-project # writes engine.default_workspace
botex config workspace none # clear it (falls back to cwd)Workspace resolution: explicit -w / workspace_dir > engine.default_workspace > current directory. BOTEX_DEFAULT_WORKSPACE overrides the config value.
Headless One-Shot Tasks
# Run a specific task
botex run "Add --verbose flag to cli.py" -w ./my-project --profile coding
# Fix a bug with a tight turn budget
botex run "Fix the failing auth test" --files tests/test_auth.py --max-turns 15
# Refactoring with destructive permissions
botex run "Clean up legacy modules" -w ./my-project --allow-destructiveConversational Chat Mode
Multi-turn discussion with token streaming, read-only tools, and automatic context pruning:
# Start interactive chat in the terminal
botex chat --model openrouter/auto
# With a custom system prompt and temperature
botex chat --system "Focus on security analysis" --temp 0.2In-chat commands: /clear (reset session), /history (review transcript), /help, /exit.
Cloud Gateway & Remote MCP (FastAPI)
Run BoteX as a background cloud daemon with SSE transport, WebSocket chat, and REST endpoints:
# Start cloud server on default port 8000
botex cloud --host 0.0.0.0 --port 8000Zero-Friction Local mode runs unauthenticated when BOTEX_ACCESS_TOKEN is unset. Set BOTEX_ACCESS_TOKEN in .env to enforce Bearer token verification on all protected endpoints.
REST surface (all under /api/): health, wallet, key/status, analytics (+POST analytics/digest), models, models/recommended, recipes, skills (+/{name}), tasks (+/{id}, /{id}/cancel, /{id}/followup, /{id}/events SSE), approvals (+/{id}/decide), memory (+/graph, /backlinks), curator/status, curator/run, rate_limits, delegation/devin, chat (+/abort, /sessions, /sessions/{id}, /sessions/{id}/save_to_memory), and WebSocket /api/chat/ws. /api/health, /api/delegation/devin, and the PWA shell stay public.
Maintenance & Observability
botex health # Verify API keys, provider connectivity, and model pricing
botex wallet # Check OpenRouter balance, key limits, and daily query caps
botex config # Inspect or modify local configuration defaults
botex --stats # View weekly token consumption and spend per model
botex --stats --month # Monthly cost report
botex --history <task_id> # Inspect exact prompts, tool calls, and diffs for a run
botex --snapshots # Check disk usage of backup snapshots
botex --clean-snapshots # Prune old snapshot backups
botex models [--refresh] # List configured provider models (refresh catalog)
botex memory <sub> # Memory vault CLI (save, search, list, ...)
botex serve # Force MCP stdio server mode explicitlyProject Structure
server.py MCP server entry point & CLI dispatcher
botex.cmd / botex.sh Zero-install launchers (auto-detects python environment)
pyproject.toml Package configuration (exposes `botex` CLI command)
requirements.txt Runtime dependencies
botex.config.json Committed defaults (providers, engine limits, exec/net policy)
ROADMAP.md Deferred features & technical rationale
botex/
approval.py Human-in-the-loop approval manager, async actions, and rollback integration
chat.py Conversational chat sessions, token streaming, and read-only sandbox
server_cloud.py FastAPI cloud gateway, Remote MCP SSE, WebSocket chat, and REST API
catalog.py Dynamic model catalog, TTL caching, and live provider query
denylist.py Hierarchical model exclusions (globs and regex)
wallet.py Key credits, spend analytics, and daily query limits
engine.py Autonomous execution loop, context management & rollback triggers
state.py In-flight task state checkpointing across model and provider fallbacks
rate_limiter.py Asynchronous token-bucket rate limiter (RPM/TPM) and cooldown tracking
curator.py Memory Vault periodic curator and Telegram dispatch
delegation.py Subagent delegation bridge (Devin ACP)
events.py Engine event emitter taxonomy
file_tools.py Safe outline-first reading, file creation, moving & deletion
patch_engine.py Fuzzy patch matching, syntax validation & snapshot management
security.py Path traversal defenses, secret masking & gitignore filtering
exec_tools.py Policy-controlled command execution & argument filtering
capabilities.py Permission presets (readonly, edit, destructive, full)
config.py Layered config loader (defaults < local < env)
context_guard.py Context compaction & verification output pruning
net_tools.py Net policy enforcement (read_url / fetch_url)
memory.py Two-tier memory vault with wikilink graph & scratchpad offload
embeddings.py Local embedding helpers for memory/graph features
obsidian.py Obsidian PKM vault export & graph index generation
meta_harness.py Task taxonomy, patch probing & meta-lesson recommendations
analytics.py Cost/token ledger, budgeting & summary reporting
pricing.py Live model price guardrail & catalog checks
providers.py Provider adapters (OpenRouter, NVIDIA, Google AI Studio, etc.) & request normalizer
retry.py Shared transient-failure backoff (429 / connection errors / Google 503 overload) & provider circuit breaker
benchmarks.py Live model recommendations (recommend_models) & task-tier estimator
contracts.py Task completion verification, status taxonomy & canonical handoff schema
tracing.py OTel-style span helpers (landed; wiring in progress)
skills.py Server-side Skill Vault, safe install/update & L0 task triage
recipes.py Recipe loading & system-prompt injection
i18n.py / ui.py CLI language & status rendering
recipes/ Specialized agent personas (planner, reviewer, tdd,
code-explorer, build-resolver, security-reviewer,
security-taint-hardener, architecture-adr, ui-craftsman)
ops/curator/ Nightly Knowledge-Graph curator service & Telegram dispatch
skills/ Caller-side SKILL.md (botex) + server-side skill packs
tests/ Comprehensive test suite (615 unit, cloud gateway, chat, approvals)
deploy/oracle-vps/ systemd units & one-click installer for Oracle A1.Flex ARM64
docs/
TUTORIAL.md Architecture deep dive and technical walkthroughTesting
Run the full local test suite (no API key required):
python -m pytest tests/All unit, approval, chat, memory, and cloud gateway tests run hermetically in offline mode.
License & Trademark
BoteX is licensed under the Apache License 2.0. See LICENSE for details. Derivative works must retain attribution notices as specified in NOTICE.
The BoteX name and logo are trademarks of Jakub Grzesiak (jg-webtech.pl). You are free to fork and modify the code under Apache-2.0, but forks or derived distributions should not use the name "BoteX" or suggest official endorsement without prior written consent.
Available Tools
18 toolscheck_healthA
Checks BoteX environment readiness (provider keys, snapshot dir, disk).
Inputs: no named parameters. Returns: result
clean_snapshotsC
Purges old or excess backup snapshots from disk.
Inputs: max_age_days, max_total_mb. Returns: result
delete_memoryA
Deletes a specific memory entry by ID from the workspace or global Memory Vault
and removes its index/graph links.
Args:
memory_id: The ID of the memory entry to delete (e.g. 'mem_a1b2c3d4').
workspace_dir: Workspace root directory. Empty = engine.default_workspace
from the config, else the server's current directory.
scope: Lookup scope ('local', 'global', or 'all'). Default is 'local'.
Inputs: memory_id (required), scope, workspace_dir. Returns: object
fetch_urlA
Fetch one public http(s) text document for caller-side research.
This tool is intentionally separate from BoteX's internal read_url: the
orchestrating agent chooses the URL, so arbitrary public hosts do not have
to be configured in net.allowed_hosts. SSRF protections, redirect
revalidation, content-type checks, byte limits, and secret masking still
apply. In net.policy='allowlist', only configured hosts may be fetched.
Inputs: url (required), max_bytes. Returns: object
find_graph_healthB
Audits Memory Vault knowledge graph integrity: reports broken links, orphan notes, and cycles.
Args:
workspace_dir: Workspace root directory.
scope: Lookup scope ('local', 'global', or 'all').
Inputs: scope, workspace_dir. Returns: object
get_backlinksA
Finds all memories that link TO the given memory_id via [[wikilinks]].
Args:
memory_id: Target memory ID (e.g. 'mem_a1b2c3d4').
workspace_dir: Workspace root directory.
scope: Lookup scope ('local', 'global', or 'all').
Inputs: memory_id (required), scope, workspace_dir. Returns: object
get_outlineA
Returns a lightweight file skeleton (classes, methods, functions, headers,
line numbers) without reading the whole file. Saves ~90% of tokens.
Inputs: path (required), workspace_dir. Returns: object
get_statsB
Returns an analytics summary of executed BoteX tasks (USD costs, token
usage, code-line balance).
Args:
period: 'week' (last 7 days) or 'month' (last 30 days).
Inputs: period. Returns: result
get_task_statusA
Return status and result for a task started with start_task.
`status` is the task lifecycle (QUEUED | RUNNING | DONE | FAILED |
CANCELLED) — DONE here means "finished", not "succeeded"; check
`result_data.status` / `result_data.ok` for the engine outcome.
`result` is the pretty-text report; `result_data` is the structured
engine result (status, failure_kind, ok, files_touched, exec_ran,
rollback_verified, attempts[], cost_usd, ...).
Inputs: task_id (required). Returns: object
init_obsidian_vaultB
Initializes or syncs Obsidian PKM vault configuration (.obsidian/graph.json, app.json)
with preset color profiles for #decision, #lesson, #handoff, #context.
Args:
workspace_dir: Workspace root directory.
scope: Target scope ('local' or 'global').
override_existing: Whether to overwrite existing .obsidian config files.
export_index: Also generate dynamic _GRAPH_INDEX.md note.
Inputs: scope, export_index, workspace_dir, override_existing. Returns: object
patch_memory_sectionA
Surgically updates a Markdown section (e.g. '## Compiled Truth') in a memory note
without modifying frontmatter, other sections, or the Timeline audit trail.
Args:
memory_id: Target memory ID to patch.
section: Section heading to replace or create (default 'Compiled Truth').
new_content: New Markdown text for the section.
workspace_dir: Workspace root directory.
scope: Lookup scope ('local' or 'global').
append: Whether to append to existing section content instead of replacing.
Inputs: memory_id (required), scope, append, section, +2 more. Returns: object
read_memoryA
Reads the full content and metadata of a specific memory entry by ID from the Memory Vault.
Args:
memory_id: The ID of the memory entry to retrieve (e.g. 'mem_a1b2c3d4').
workspace_dir: Workspace root directory. Empty = engine.default_workspace
from the config, else the server's current directory.
scope: Lookup scope ('local', 'global', or 'all'). Default is 'local'.
Inputs: memory_id (required), scope, workspace_dir. Returns: object
read_scratchpadA
Reads the full execution or terminal log offloaded to the scratchpad (.botex/scratchpad/<memory_id>.log).
Args:
memory_id: The ID of the scratchpad entry (e.g. 'mem_exec_a1b2c3d4').
workspace_dir: Workspace root directory. Empty = engine.default_workspace
from the config, else the server's current directory.
Inputs: memory_id (required), workspace_dir. Returns: object
recommend_modelsA
[EN] Fetches the most cost-effective and capable models from OpenRouter based on live benchmarks.
USE THIS TOOL BEFORE calling `run_subagent` if you are unsure which model ID to use or want to optimize for cost/quality.
include_free=True also admits ':free' variants (non-ZDR — prompts may be
logged/trained on); they require allow_non_zdr or the openrouter-free
provider to actually run.
[PL] Pobiera rekomendacje modeli z OpenRouter na podstawie benchmarków.
Użyj tego narzędzia ZANIM wywołasz `run_subagent`, jeśli nie znasz dokładnego ID modelu.
include_free=True dopuszcza warianty ':free' (non-ZDR — prompty mogą być
logowane/trenowane); do uruchomienia wymagają allow_non_zdr albo
providera openrouter-free.
Inputs: tier, limit, recipe, profile, +3 more. Returns: result
run_subagentA
Runs BoteX — an autonomous code execution engine (agent-agnostic harness).
BoteX performs multi-step tasks on local files inside workspace_dir.
TIP: If the user didn't specify a model, DO NOT guess. Use the `recommend_models` tool first to find the best model for this task!
Key engine features:
- Outline-First and Context Pruning: ~90% token savings.
- Pre-write Syntax Check: in-memory code validation before touching disk.
- Multi-tier Fuzzy Patching: tolerant of CRLF/LF and indentation drift.
- Hard Zero-Retention on OpenRouter (provider: data_collection=deny)
and DLP secret censoring.
- Automatic Snapshot Rollback on loops or critical failures.
Args:
task: Precise description of the coding or refactoring task.
files: Optional list of primary files affected by the task.
workspace_dir: Project directory path. Empty = engine.default_workspace
from the config, else the server's current directory.
model: Any model from the provider's catalog. Empty = model from config
(see 'profile' and botex.config.json).
profile: Model profile from botex.config.json (e.g. 'default', 'coding',
'auto-beta', 'fast'). When both 'model' and 'profile' are empty,
the capability mode picks the tier via engine.mode_profiles
(readonly -> 'fast', destructive/full -> 'coding'). Ignored when
'model' is given explicitly.
provider: API provider from the 'providers' section of botex.config.json
('openrouter', 'nvidia', 'google', 'openrouter-free', 'ollama').
Empty = provider marked 'default: true' in the configuration.
mode: Capability preset: 'readonly' (read only — the contract is an
analysis report, DONE requires non-empty findings), 'edit'
(read + edit — default), 'destructive' (+delete/move),
'full' (+run_command). Empty = engine.default_mode from
config. Explicit allow_* flags may only WIDEN a preset —
they never narrow it (readonly can never gain file writes).
In headless mode this is pre-authorization — grant it
consciously.
max_turns: Maximum tool-loop steps (0 = config value).
max_tokens: Per-turn completion cap (0 = config value; reasoning
models need ~8000+ since thinking shares this budget).
max_duration_s: Total wall-clock limit in seconds (0 = config value,
0 disables only when config is also 0). Checked between turns.
budget_limit_usd: Daily spend limit in USD (negative = config value,
0 = no limit).
allow_destructive: Authorize destructive operations (delete_file/
move_file) for this task. Headless mode cannot confirm
mid-run — grant ONLY with the user's consent.
allow_exec: Authorize run_command for this task (also requires
exec.enabled=true in config). WARNING: this is NOT a sandbox —
commands run with operator privileges. Grant only for trusted
workspaces with the user's consent.
api_key: Optional provider API key passed per-request (highest
priority — overrides env/.env/config). Empty = resolved
internally by the harness.
output_path: Optional required output file (workspace-relative).
Sets the file_output contract: DONE is accepted only when
the file exists on disk, is non-empty, and passes the
syntax gate; a DONE response carrying the payload as text
is salvaged to disk. Requires a mutating mode.
allow_net: Explicitly authorizes the read-only public web tool for
this run. It is never enabled by a capability mode.
net_allowed_hosts: Optional per-run host authorization. In
net.policy='caller' these replace config defaults; in 'public'
they narrow public access; in 'allowlist' they must stay inside
net.allowed_hosts.
net_allowed_urls: Optional per-run URL authorization rules. A URL
ending in '/' authorizes that subtree; otherwise it authorizes
the exact URL including its query string.
verify_command: Optional allowlisted command that must pass before
DONE is accepted — it runs against the workspace as it
stands, including when the task made no writes (a passing
verifier validates a legitimate no-change result). Requires
exec.enabled=true in config and exec authorization.
recipe: Optional operational persona / workflow prompt (e.g. 'planner',
'code-explorer', 'reviewer', 'security-reviewer', 'build-resolver', 'tdd').
allow_non_zdr: Per-run consent to relax the Zero Data Retention
gate. Required for free (:free) models whose endpoints may
log or train on prompts — it also switches the wire
provider.data_collection flag to 'allow'. Grant only with
the operator's consent; the result carries
zdr_enforced=false. The openrouter-free provider preset is
the persistent config-level alternative.
approval_policy: Operator approval policy for risky operations: 'none',
'high_risk' (default), 'mutations', 'all_risky'.
Returns:
A pretty-text report in the text content (unchanged format for legacy
clients) plus the full engine result as structuredContent (status,
failure_kind, ok, files_touched, exec_ran, rollback_verified,
attempts[], cost_usd, ...). `ok` is true only when status == DONE —
i.e. the task contract was verified, not merely claimed by the model.
Inputs: task (required), mode, files, model, +18 more. Returns: Structured result of a finished BoteX run. `status` is one of the engine status…
save_memoryA
Saves a persistent context note, architectural decision, task handoff, or lesson
into the workspace or global shared Memory Vault.
Masks secrets and provides directory isolation.
Args:
title: Short descriptive title of the memory entry.
content: Detailed markdown notes, architectural rationale, or handoff context.
workspace_dir: Workspace root directory. Empty = engine.default_workspace
from the config, else the server's current directory.
kind: Entry category ('context' | 'decision' | 'handoff' | 'lesson').
tags: Optional list of keyword tags for filtering and discovery.
memory_id: Optional custom identifier (alphanumeric/hyphen/underscore). Auto-generated if omitted.
scope: Storage scope ('local' for workspace, 'global' for cross-workspace). Default is 'local'.
Inputs: title (required), content (required), kind, tags, +3 more. Returns: object
search_memoryA
Searches the Memory Vault by keyword query, tag, or entry kind
(context, decision, handoff, lesson) across local, global, or all scopes.
Args:
workspace_dir: Workspace root directory. Empty = engine.default_workspace
from the config, else the server's current directory.
query: Free-text search string matched against title, content, and tags.
tag: Filter by specific tag.
kind: Filter by entry kind ('context', 'decision', 'handoff', 'lesson').
scope: Search scope ('local', 'global', or 'all'). Default is 'local'.
Inputs: tag, kind, query, scope, +1 more. Returns: object
start_taskA
Start a detached BoteX task and return its task_id immediately.
Runs the same engine as `run_subagent`, but returns instantly with a
`task_id` for polling via `get_task_status`. Concurrency is bounded by
engine.max_concurrent_tasks and the queue by engine.max_queued_tasks —
a full queue returns status TOO_MANY_QUEUED.
The capability/limits arguments are identical to `run_subagent` —
same contracts, same pre-authorization semantics:
- mode: capability preset — 'readonly' (read tools only; the contract
is an analysis report), 'edit' (read + write; default), 'destructive'
(+ delete/move), 'full' (+ run_command). Empty = engine.default_mode.
- allow_destructive / allow_exec / allow_net only ever WIDEN the
preset, never narrow it — a readonly task cannot gain file writes.
allow_exec additionally requires exec.enabled=true in the config.
None of these is a sandbox: grant them only with the user's consent.
- output_path makes the contract file_output: DONE requires the file
to exist, be non-empty, and pass the syntax gate (mutating mode).
- verify_command is an allowlisted command that must pass before DONE
is accepted — it runs even when the task made no writes. Requires
exec authorization.
- recipe: Optional operational persona / workflow prompt (e.g. 'planner',
'code-explorer', 'reviewer', 'security-reviewer', 'build-resolver', 'tdd').
- max_turns / max_tokens / max_duration_s / budget_limit_usd:
0 (negative for budget) = config value; a non-positive max_turns is
clamped to 1.
- net_allowed_hosts / net_allowed_urls narrow or replace the net
scope per run according to net.policy (see run_subagent).
- allow_non_zdr: per-run consent to relax Zero Data Retention — needed
for free (:free) models whose endpoints may log or train on prompts.
Same semantics as in run_subagent.
Returns:
{"task_id": str, "status": "QUEUED"} — poll with get_task_status.
The finished task's `result_data` carries the full engine result
(status, failure_kind, ok, files_touched, exec_ran,
rollback_verified, attempts[], cost_usd, ...).
Inputs: task (required), mode, files, model, +17 more. Returns: object
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 18 tools
Most tools have clearly distinct targets: memory CRUD (save/search/read/delete/patch), graph tools (get_backlinks, find_graph_health), admin (check_health, clean_snapshots, get_stats), and file/web access (get_outline, fetch_url). The main friction point is run_subagent vs start_task, which expose nearly identical argument surfaces and differ only in sync vs detached execution — well documented, but an easy misselection. search_memory vs read_memory vs read_scratchpad are separable but require reading descriptions to distinguish.
Every tool follows a consistent snake_case verb_noun pattern (fetch_url, get_task_status, save_memory, patch_memory_section, init_obsidian_vault). Verbs are used predictably (get_* for retrieval, *_memory for vault ops, run_/start_ for engine invocation). No camelCase or stylistic outliers.
18 tools is on the heavier side but each maps to a real capability across three sub-domains (engine execution, memory vault, environment/admin). Nothing looks like filler, though the admin trio (check_health, clean_snapshots, get_stats) plus Obsidian init could plausibly be consolidated. Slightly over-scoped rather than bloated.
Memory vault coverage is strong (create/read/search/patch/delete/backlinks/graph-health/Obsidian export) and the task lifecycle covers start, poll, and synchronous run. The notable gap is the absence of a cancel_task tool even though CANCELLED is an advertised status, and there is no explicit list_memories or full-content update (only section patching) — agents can mostly work around these via search_memory and max_duration_s.
Maintenance
Related MCP Connectors
A paid remote MCP for OpenAI Codex agent coordination MCP, built to return verdicts, receipts, usage
Control plane for autonomous software labor. Agents claim objectives over MCP with audit trail.
Hosted MCP server and Agent Skills for specs, engineering threads, and project memory.
Build and publish full-stack apps from your coding agent: models, rules, pages, auth, per-app MCP.
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceEnables MCP-capable coding assistants to delegate repository investigation, bounded implementation work, and noisy command runs (tests, builds, linters) to sandboxed OpenCode agents. Each role can use an independently selected model, and only concise results are returned to the parent agent, which keeps responsibility for architecture and high-risk operations.MIT
- AlicenseNot gradedqualityCmaintenanceEnables MCP clients like Codex and DSH to invoke DeepSeek subagents for inspect, plan, review, and implement tasks, with write protection, rollback, and status reporting.1,160 npmMIT
- AlicenseNot gradedqualityCmaintenanceEnables MCP clients to route coding tasks across local and cloud models with explicit budgets, repository planning and execution, and independent validation/repair checks.Apache 2.0
- AlicenseNot gradedqualityCmaintenanceEnables delegating tasks to agents you configure yourself through OpenAI-compatible Chat Completions backends, with automatic or explicit routing, synchronous calls, persistent asynchronous jobs, and multi-step reviewed workflows. It returns proposals and analyses only, leaving file changes, command execution, and approvals under the MCP client's control.18 npmMIT