Skip to content

Latest commit

 

History

History
875 lines (710 loc) · 36.3 KB

File metadata and controls

875 lines (710 loc) · 36.3 KB

Tools Configuration

MintClaw's tools configuration is located in the tools field of config.json.

Related: Per-agent tool filtering is configured in each agent's AGENT.md frontmatter, not under the top-level tools section. See the Configuration Guide.

Directory Structure

{
  "tools": {
    "web": {
      ...
    },
    "mcp": {
      ...
    },
    "exec": {
      ...
    },
    "cron": {
      ...
    },
    "skills": {
      ...
    }
  }
}

Sensitive Data Filtering

Before tool results are sent to the LLM, MintClaw can filter sensitive values (API keys, tokens, secrets) from the output. This prevents the LLM from seeing its own credentials.

See Sensitive Data Filtering for full documentation.

Config Type Default Description
filter_sensitive_data bool true Enable/disable filtering
filter_min_length int 8 Minimum content length to trigger filtering

Tool Approvals

Tool approvals default to required. To run an explicitly trusted deployment without approval prompts, set:

{
  "tools": {
    "approval": {
      "mode": "allow_all"
    }
  }
}
Config Type Default Description
tools.approval.mode string required required uses approval hooks and operator confirmation; allow_all bypasses both
tools.approval.bypass_node_targets string[] [] Exact node target aliases that bypass tool and operator approval while mode remains required

allow_all is a global unattended-operation mode. It bypasses only the approval boundary. Pairing, target/profile authorization, discovery revisions, node policy, broker identity checks, and timeout/output limits still apply. Subagents also remain limited to targets and profiles granted to them. Run mintclaw doctor to surface this mode as a high-risk finding.

To bypass approval only for explicitly trusted node targets, keep the global mode at required and list their configured execution-target aliases:

{
  "tools": {
    "approval": {
      "mode": "required",
      "bypass_node_targets": ["vpn"]
    }
  }
}

The bypass applies to every current or future first-party node tool carrying MintClaw's internal trusted-node capability when its call explicitly includes an exact listed target. An injected or replacement tool cannot gain the bypass by using a nodes_* name or wrapping a first-party tool. The validated tool instance is bound through execution, so a concurrent registry replacement cannot inherit its approval. Other targets, calls that omit the target, and non-node tools continue through the configured approval hooks. Target aliases must exist in execution.targets; duplicates, unknown targets, and combining bypass_node_targets with allow_all are rejected. mintclaw doctor reports the scoped bypass as a high-risk finding.

Request User Input

The built-in request_user_input tool lets foreground turns and durable background tasks pause for an authorized user answer and resume across process restarts.

Config Type Default Description
tools.request_user_input.enabled bool true Allow new model-requested questions
tools.request_user_input.default_timeout_seconds int 3600 Default wait, from 60 seconds to the configured maximum
tools.request_user_input.max_timeout_seconds int 86400 Maximum model-requested wait, at most 24 hours
tools.request_user_input.retention_hours int 168 Retain terminal interaction records before pruning

Disabling the tool prevents new questions but does not discard pending durable state. Human approval remains opt-in through a trusted approval hook.

See Durable Human Interaction for answer formats, approval behavior, restart semantics, storage, and debugging.

Web Tools

Web tools are used for web search and fetching.

Web Fetcher

General settings for fetching and processing webpage content.

Config Type Default Description
enabled bool true Enable the webpage fetching capability.
fetch_limit_bytes int 10485760 Maximum size of the webpage payload to fetch, in bytes (default is 10MB).
format string "plaintext" Output format of the fetched content. Options: plaintext or markdown (recommended).

Brave

Config Type Default Description
enabled bool false Enable Brave search
api_key string - Brave Search API key
api_keys string[] - Multiple API keys for rotation (takes priority over api_key)
max_results int 5 Maximum number of results

DuckDuckGo

Config Type Default Description
enabled bool true Enable DuckDuckGo search
max_results int 5 Maximum number of results

Gemini Google Search

Gemini search uses Gemini with Google Search grounding. It returns an AI-synthesized answer with citations from Google Search.

Config Type Default Description
enabled bool false Enable Gemini Google Search
api_key string - Google Gemini API key
model string gemini-2.5-flash Gemini model used for search
max_results int 5 Maximum number of citations
{
  "tools": {
    "web": {
      "gemini": {
        "enabled": true,
        "api_key": "YOUR_GEMINI_API_KEY",
        "model": "gemini-2.5-flash",
        "max_results": 5
      }
    }
  }
}

Baidu Search

Baidu Search uses the Qianfan AI Search API, which is AI-powered and optimized for Chinese-language queries.

Config Type Default Description
enabled bool false Enable Baidu Search
api_key string - Qianfan API key
base_url string https://qianfan.baidubce.com/v2/ai_search/web_search Baidu Search API URL
max_results int 5 Maximum number of results
{
  "tools": {
    "web": {
      "baidu_search": {
        "enabled": true,
        "api_key": "YOUR_BAIDU_QIANFAN_API_KEY",
        "max_results": 10
      }
    }
  }
}

Perplexity

Config Type Default Description
enabled bool false Enable Perplexity search
api_key string - Perplexity API key
api_keys string[] - Multiple API keys for rotation (takes priority over api_key)
max_results int 5 Maximum number of results

Kagi Search

Kagi Search uses the official Kagi OpenAPI client for POST /search and returns normal web results from data.search.

Config Type Default Description
enabled bool false Enable Kagi Search
api_key string - Kagi API key
api_keys string[] - Multiple API keys for rotation (takes priority over api_key)
base_url string https://kagi.com/api/v1/search Kagi Search API endpoint
max_results int 5 Maximum number of results
{
  "tools": {
    "web": {
      "provider": "kagi",
      "kagi": {
        "enabled": true,
        "max_results": 5,
        "base_url": "https://kagi.com/api/v1/search"
      }
    }
  }
}

Store Kagi API keys in .security.yml:

web:
  kagi:
    api_keys:
      - "YOUR_KAGI_API_KEY"

Kagi API usage may be billed or limited separately from a normal Kagi subscription, depending on your account and API setup.

Tavily

Config Type Default Description
enabled bool false Enable Tavily search
api_key string - Tavily API key
base_url string - Custom Tavily API base URL
max_results int 5 Maximum number of results

SearXNG

Config Type Default Description
enabled bool false Enable SearXNG search
base_url string http://localhost:8888 SearXNG instance URL
max_results int 5 Maximum number of results

GLM Search

Config Type Default Description
enabled bool false Enable GLM Search
api_key string - GLM API key
base_url string https://open.bigmodel.cn/api/paas/v4/web_search GLM Search API URL
search_engine string search_std Search engine type
max_results int 5 Maximum number of results

Additional Web Settings

Config Type Default Description
prefer_native bool true Prefer provider's native search over configured search engines
private_host_whitelist string[] [] Private/internal hosts allowed for web fetching

web_search Tool Parameters

At runtime, the web_search tool accepts the following parameters:

Field Type Required Description
query string yes Search query string
count integer no Number of results to return. Default: 10, max: 10
range string no Optional time filter: d (day), w (week), m (month), y (year)

If range is omitted, MintClaw performs an unrestricted search. For Kagi, d, w, and m map to Kagi lens time_relative; y maps to a lens time_after date one year before the current day.

Example web_search Call

{
  "query": "ai agent news",
  "count": 10,
  "range": "w"
}

Image Generation Tool

The image_generate tool creates image files through a provider that supports image generation.

Config Type Default Description
enabled bool false Enable the image generation tool
model string gpt-image-2 Image generation model. Values may include a provider prefix, for example openai-codex/gpt-image-2

tools.image_generate.model is configured independently from vision / load_image routing. If it is not set, MintClaw uses gpt-image-2.

{
  "tools": {
    "image_generate": {
      "enabled": true,
      "model": "openai-codex/gpt-image-2"
    }
  }
}

Apply Patch Tool

The apply_patch tool applies structured multi-file edits using the Codex patch format. It is the preferred tool for targeted edits and changes spanning multiple files.

Config Type Default Description
tools.apply_patch.enabled bool true Enable the apply_patch file-editing tool

apply_patch uses the same workspace restriction and tools.allow_write_paths rules as write_file and append_file.

apply_patch Tool Parameters

Field Type Required Description
input string yes Full patch text including *** Begin Patch and *** End Patch

Supported operations:

  • *** Add File: path
  • *** Update File: path
  • *** Delete File: path

Example:

*** Begin Patch
*** Update File: app.go
@@
-fmt.Println("old")
+fmt.Println("new")
*** End Patch

Search Files Tool

The search_files tool searches workspace files without shelling out to grep, rg, find, or ls. It is intended for routine repository and workspace discovery while preserving MintClaw's read workspace restrictions and tools.allow_read_paths. It respects .gitignore by default so normal search does not drown in generated/cache/runtime files. This is a noise filter, not a security boundary; use include_ignored: true only when explicitly inspecting ignored environment, configuration, and runtime files.

Config Type Default Description
tools.search_files.enabled bool true Enable the search_files file-search tool

search_files Tool Parameters

Field Type Required Description
pattern string yes Regex pattern for content search, or glob/name pattern for file search
target string no content or files; default content
path string no Directory or file to search; default .
file_glob string no Restrict content search to matching file names, such as *.go
output_mode string no content, files_only, or count; default content
context int no Context lines around content matches; default 0, max 10
limit int no Maximum returned matches/files; default 100, max 500
include_ignored bool no Include .gitignored files and default noisy dirs such as node_modules; default false

When results are incomplete because of a result count limit, byte limit, max file size skip, or ignored-path exclusion, search_files appends a Search truncation block. The block includes truncated=true, the reason, returned count, configured limit, total omitted result rows when known, reason-specific sub-counts such as count_limit_omitted_count and rendered_omitted_count, separate skipped counts for ignored or max-size files, and suggestions to narrow by path, file_glob, or pattern. For ignored/runtime files, rerun with include_ignored: true only when those files are explicitly needed.

Examples:

{"pattern": "NewAgentInstance", "path": "pkg", "file_glob": "*.go"}
{"target": "files", "pattern": "*.md", "path": "docs"}
{"pattern": "OPENAI_API_KEY", "path": ".", "file_glob": ".env*", "include_ignored": true}

Exec Tool

The exec tool is used to execute shell commands.

Config Type Default Description
enabled bool true Enable the exec tool
enable_deny_patterns bool true Enable default dangerous command blocking
permission_mode string "" Optional mode. Use read_only to allow only commands classified as read-only
custom_deny_patterns array [] Custom deny patterns (regular expressions)

Disabling the Exec Tool

To completely disable the exec tool, set enabled to false:

Via config file:

{
  "tools": {
    "exec": {
      "enabled": false
    }
  }
}

Via environment variable:

MINTCLAW_TOOLS_EXEC_ENABLED=false

Note: When disabled, the agent will not be able to execute shell commands. This also affects the Cron tool's ability to run scheduled shell commands.

Functionality

  • enable_deny_patterns: Set to false to completely disable the default dangerous command blocking patterns
  • permission_mode: Set to read_only to block write, destructive, and unknown commands after deny/allow/path checks. Leave empty for the default behavior.
  • custom_deny_patterns: Add custom deny regex patterns; commands matching these will be blocked

Default Blocked Command Patterns

By default, MintClaw blocks the following dangerous commands:

  • Delete commands: rm -rf, del /f/q, rmdir /s
  • Disk operations: format, mkfs, diskpart, dd if=, writing to /dev/sd*
  • System operations: shutdown, reboot, poweroff
  • Command substitution: $(), ${}, backticks
  • Pipe to shell: | sh, | bash
  • Privilege escalation: sudo, chmod, chown
  • Process control: pkill, killall, kill -9
  • Remote operations: curl | sh, wget | sh, ssh
  • Package management: apt, yum, dnf, npm install -g, pip install --user
  • Containers: docker run, docker exec
  • Git: git push, git force
  • Other: eval, source *.sh

Known Architectural Limitation

The exec guard only validates the top-level command sent to MintClaw. It does not recursively inspect child processes spawned by build tools or scripts after that command starts running.

Examples of workflows that can bypass the direct command guard once the initial command is allowed:

  • make run
  • go run ./cmd/...
  • cargo run
  • npm run build

This means the guard is useful for blocking obviously dangerous direct commands, but it is not a full sandbox for unreviewed build pipelines. If your threat model includes untrusted code in the workspace, use stronger isolation such as containers, VMs, or an approval flow around build-and-run commands.

Configuration Example

{
  "tools": {
    "exec": {
      "enable_deny_patterns": true,
      "custom_deny_patterns": [
        "\\brm\\s+-r\\b",
        "\\bkillall\\s+python"
      ]
    }
  }
}

Update Plan Tool

The update_plan tool lets the agent publish structured progress for multi-step tasks. It mirrors OpenClaw's planning helper: the tool records the current ordered plan, validates step statuses, and returns the updated plan to the model without performing any external side effects.

Config Type Default Description
tools.update_plan.enabled bool false Register the agent-facing update_plan tool

When update_plan is enabled, the tool description tells the model to use it only for non-trivial multi-step work, keep exactly one in_progress step while work is active, and avoid repeating the whole plan after each update.

update_plan Tool Parameters

Field Type Required Description
explanation string no Short note explaining what changed in the plan
plan array yes Ordered list of plan steps
plan[].step string yes Short plan step
plan[].status string yes One of pending, in_progress, or completed

At most one step may be in_progress. The tool is intended for visible coordination during longer tasks; it does not run steps, schedule work, or replace workflow engines such as cron, MCP servers, or external orchestration.

Example update_plan Call

{
  "explanation": "Implementation has started.",
  "plan": [
    { "step": "Inspect existing tools", "status": "completed" },
    { "step": "Add update_plan tool", "status": "in_progress" },
    { "step": "Run focused tests", "status": "pending" }
  ]
}

Cron Tool

The cron tool is used for scheduling periodic tasks.

Config Type Default Description
enabled bool true Register the agent-facing cron tool
allow_command bool true Allow command jobs without extra confirmation
command_allowed_remotes string[] [] Remote channels or channel:chat_id values allowed for command jobs; * allows every channel and is dangerous unless all remote channels are trusted
exec_timeout_minutes int 5 Execution timeout in minutes, 0 means no limit

For schedule types, execution modes (deliver, agent turn, and command jobs), persistence, and the current command-security gates, see Scheduled Tasks and Cron Jobs.

MCP Tool

The MCP tool enables integration with external Model Context Protocol servers.

If you prefer not to edit JSON manually, MintClaw also provides an MCP configuration manager CLI:

  • mintclaw mcp add — add or update a server (supports --deferred / --no-deferred)
  • mintclaw mcp list — list all configured servers with status and deferred state
  • mintclaw mcp show <name> — show full details and the tool list for one server
  • mintclaw mcp test <name> — connectivity check for one server
  • mintclaw mcp remove <name> — remove a server entry
  • mintclaw mcp edit — open config.json in $EDITOR for advanced edits

These commands manage the same tools.mcp.servers section documented below. See MCP Server CLI for command syntax, examples, and behavior details.

Tool Discovery (Lazy Loading)

When connecting to multiple MCP servers, exposing hundreds of tools simultaneously can exhaust the LLM's context window and increase API costs. The Discovery feature solves this by keeping MCP tools hidden by default.

Instead of loading all tools, the LLM is provided with a lightweight search tool (using BM25 keyword matching or Regex). When the LLM needs a specific capability, it searches the hidden library. Matching tools are then temporarily "unlocked" and injected into the context for a configured number of turns (ttl).

Global Config

Config Type Default Description
enabled bool false Enable MCP integration globally
discovery object {} Configuration for Tool Discovery (see below)
servers object {} Map of server name to server config

Discovery Config (discovery)

Config Type Default Description
enabled bool false Global default: if true, all MCP tools are hidden and loaded on-demand via search; if false, all tools are loaded into context. Individual servers can override this with the per-server deferred field.
ttl int 5 Number of conversational turns a discovered tool remains unlocked
max_search_results int 5 Maximum number of tools returned per search query
use_bm25 bool true Enable the natural language/keyword search tool (tool_search_tool_bm25). Warning: consumes more resources than regex search
use_regex bool false Enable the regex pattern search tool (tool_search_tool_regex)

Note: If discovery.enabled is true, you MUST enable at least one search engine (use_bm25 or use_regex), otherwise the application will fail to start.

Per-Server Config

Config Type Required Description
enabled bool yes Enable this MCP server
deferred bool no Override deferred mode for this server only. true = tools are hidden and discoverable via search; false = tools are always visible in context. When omitted, the global discovery.enabled value applies.
type string no Transport type: stdio, sse, http
command string stdio Executable command for stdio transport
args array no Command arguments for stdio transport
env object no Environment variables for stdio process
env_file string no Path to environment file for stdio process
url string sse/http Endpoint URL for sse/http transport
headers object no HTTP headers for sse/http transport
session_loss_replay string no once (default) reconnects and invokes an interrupted call once; never reconnects for future calls but returns the interrupted call as uncertain without replay
exclusive_lock_file string no Absolute path to an operator-owned, non-blocking exclusive lease for a stdio server; omitted by default

Transport Behavior

  • If type is omitted, transport is auto-detected:
    • url is set → sse
    • command is set → stdio
  • http and sse both use url + optional headers.
  • env and env_file are only applied to stdio servers.
  • Use session_loss_replay: "never" for servers whose tools may have external effects that cannot be safely repeated after a lost response.
  • Use exclusive_lock_file when a stdio server owns a persistent resource such as a browser profile. Its parent directory must already exist. MintClaw holds the OS lock across reconnects and releases it when the manager closes; remote HTTP/SSE servers reject this setting.

Configuration Examples

1) Stdio MCP server

{
  "tools": {
    "mcp": {
      "enabled": true,
      "servers": {
        "filesystem": {
          "enabled": true,
          "command": "npx",
          "args": [
            "-y",
            "@modelcontextprotocol/server-filesystem",
            "/tmp"
          ]
        }
      }
    }
  }
}

2) Remote SSE/HTTP MCP server

{
  "tools": {
    "mcp": {
      "enabled": true,
      "servers": {
        "remote-mcp": {
          "enabled": true,
          "type": "sse",
          "url": "https://example.com/mcp",
          "headers": {
            "Authorization": "Bearer YOUR_TOKEN"
          }
        }
      }
    }
  }
}

3) Massive MCP setup with Tool Discovery enabled

In this example, the LLM will only see the tool_search_tool_bm25. It will search and unlock Github or Postgres tools dynamically only when requested by the user.

{
  "tools": {
    "mcp": {
      "enabled": true,
      "discovery": {
        "enabled": true,
        "ttl": 5,
        "max_search_results": 5,
        "use_bm25": true,
        "use_regex": false
      },
      "servers": {
        "github": {
          "enabled": true,
          "command": "npx",
          "args": [
            "-y",
            "@modelcontextprotocol/server-github"
          ],
          "env": {
            "GITHUB_PERSONAL_ACCESS_TOKEN": "YOUR_GITHUB_TOKEN"
          }
        },
        "postgres": {
          "enabled": true,
          "command": "npx",
          "args": [
            "-y",
            "@modelcontextprotocol/server-postgres",
            "postgresql://user:password@localhost/dbname"
          ]
        },
        "slack": {
          "enabled": true,
          "type": "slack",
          "command": "npx",
          "args": [
            "-y",
            "@modelcontextprotocol/server-slack"
          ],
          "env": {
            "SLACK_BOT_TOKEN": "YOUR_SLACK_BOT_TOKEN",
            "SLACK_TEAM_ID": "YOUR_SLACK_TEAM_ID"
          }
        }
      }
    }
  }
}

4) Mixed setup: per-server deferred override

Discovery is enabled globally, but filesystem is pinned as always-visible while context7 follows the global default (deferred). aws explicitly opts in to deferred mode even though it is the same as the global default.

{
  "tools": {
    "mcp": {
      "enabled": true,
      "discovery": {
        "enabled": true,
        "ttl": 5,
        "max_search_results": 5,
        "use_bm25": true
      },
      "servers": {
        "filesystem": {
          "enabled": true,
          "command": "npx",
          "args": ["-y", "@modelcontextprotocol/server-filesystem", "/workspace"],
          "deferred": false
        },
        "context7": {
          "enabled": true,
          "command": "npx",
          "args": ["-y", "@upstash/context7-mcp"]
        },
        "aws": {
          "enabled": true,
          "command": "npx",
          "args": ["-y", "aws-mcp-server"],
          "deferred": true
        },
        "inventorydb": {
          "enabled": true,
          "command": "/path/to/inventorydb-mcp",
          "deferred": true,
          "visible_tools": [
            "mcp_inventorydb_shopping_add_item",
            "mcp_inventorydb_shopping_list_items",
            "mcp_inventorydb_shopping_update_items"
          ]
        }
      }
    }
  }
}

Tip: deferred on a per-server basis is independent of discovery.enabled. You can keep discovery.enabled: false globally (all tools visible by default) and still mark individual high-volume servers as "deferred": true to avoid polluting the context with their tools.

When a server stays deferred, visible_tools can keep a small allowlist of directly visible MCP tools while all other tools from that server remain hidden behind discovery.

Skills Tool

The skills tool configures skill discovery and installation via registries like ClawHub and GitHub.

Registries

Config Type Default Description
registries.clawhub.enabled bool true Enable ClawHub registry
registries.clawhub.base_url string https://clawhub.ai ClawHub base URL
registries.clawhub.auth_token string "" Optional Bearer token for higher rate limits
registries.clawhub.search_path string "" Search API path
registries.clawhub.skills_path string "" Skills API path
registries.clawhub.download_path string "" Download API path
registries.clawhub.timeout int 0 Request timeout in seconds (0 = default)
registries.clawhub.max_zip_size int 0 Max skill zip size in bytes (0 = default)
registries.clawhub.max_response_size int 0 Max API response size in bytes (0 = default)
registries.github.enabled bool true Enable GitHub installs via registry config
registries.github.base_url string https://github.com GitHub or GitHub Enterprise base URL
registries.github.auth_token string "" GitHub personal access token
registries.github.proxy string "" HTTP proxy for GitHub API requests

Legacy GitHub Config

github.* is deprecated. Use registries.github.* instead. The legacy fields are still supported for compatibility and will be removed later.

Config Type Default Description
github.base_url string https://github.com Deprecated GitHub base URL
github.proxy string "" Deprecated GitHub proxy
github.token string "" Deprecated GitHub token

Search Settings

Config Type Default Description
max_concurrent_searches int 2 Max concurrent skill search requests
search_cache.max_size int 50 Max cached search results
search_cache.ttl_seconds int 300 Cache TTL in seconds

Configuration Example

{
  "tools": {
    "skills": {
      "registries": {
        "clawhub": {
          "enabled": true,
          "base_url": "https://clawhub.ai",
          "auth_token": "",
	          "search_path": "",
	          "skills_path": "",
	          "download_path": "",
	          "timeout": 0,
	          "max_zip_size": 0,
	          "max_response_size": 0
        },
        "github": {
          "enabled": true,
          "base_url": "https://github.com",
	          "auth_token": "",
	          "proxy": ""
        }
      },
      "github": {
	        "base_url": "https://github.com",
        "proxy": "",
        "token": ""
      },
      "max_concurrent_searches": 2,
      "search_cache": {
        "max_size": 50,
        "ttl_seconds": 300
      }
    }
  }
}

Environment Variables

All configuration options can be overridden via environment variables with the format MINTCLAW_TOOLS_<SECTION>_<KEY>:

For example:

  • MINTCLAW_TOOLS_WEB_BRAVE_ENABLED=true
  • MINTCLAW_TOOLS_EXEC_ENABLED=false
  • MINTCLAW_TOOLS_EXEC_ENABLE_DENY_PATTERNS=false
  • MINTCLAW_TOOLS_CRON_EXEC_TIMEOUT_MINUTES=10
  • MINTCLAW_TOOLS_MCP_ENABLED=true
  • MINTCLAW_TOOLS_MCP_MAX_INLINE_TEXT_CHARS=16384

Note: Nested map-style config (for example tools.mcp.servers.<name>.*) is configured in config.json rather than environment variables.

For MCP tools, tools.mcp.max_inline_text_chars controls how much text result is kept inline in model context. The threshold is counted in Unicode characters (Go runes), not bytes. For example, 16384 means up to 16,384 characters inline, which may occupy more than 16 KB for multibyte text such as CJK. Above this threshold, MintClaw saves the MCP text result as a local artifact in the agent workspace and gives the model a short note plus a structured [file:...] artifact path instead of injecting the full payload into context. The artifact is registered in MediaStore as text/plain with delete-on-cleanup ownership, so tools.media_cleanup TTL cleanup removes the exact managed file. If registration fails, MintClaw deletes the new file and returns only a bounded omission note.

tools.media_cleanup.max_age_minutes controls how long media:// references and their managed files remain available. The default is 10,080 minutes (7 days). Inbound files downloaded into MintClaw's temporary media directory are promoted into the workspace's persistent state/media/files directory before registration, so their references survive gateway restarts and host reboots until the retention window expires. Historical images are represented in prompts by lightweight path tags rather than being reattached as base64; the agent can explicitly open them with load_image when the user refers back to an earlier image.