QueryMT Agent - Configuration Guide
This guide covers the TOML configuration format for QueryMT Agent. Configuration can be loaded from files or specified inline.
Configuration Overview
Agent configuration is defined in TOML format with the following structure:
Loading Configuration
From File
From String
Embedded Configuration
The qmtcode example uses embedded configuration:
Single Agent Configuration
Agent Settings
For reusable system-prefix annotations, TTL behavior, and provider limitations, see Prompt Cache Hints.
Execution Policy
Skills Configuration
Hooks Configuration
Hooks run configured local commands at specific agent lifecycle points. They are configured directly in [agent.hooks], which makes them a natural fit for profiles.
Hook commands receive JSON on stdin and return JSON on stdout. Supported events now include compaction hooks and delegation hooks in addition to tool, prompt, session, permission, and stop hooks. See the Hooks Guide for the full event list, schema files, and stop continuation behavior.
Workspace (Git worktree) Configuration
Managed Git worktree isolation is disabled by default. Enabling it only makes isolation available; sessions still run locally unless they explicitly ask for a worktree.
baseline is a default for explicitly requested top-level isolation that does
not choose its own baseline. Invalid settings (unusable storage_root, a
backend without a workspace repository) fail when the agent is built. See
Git Worktree Workspaces for requesting isolation, the error
codes, and the Rust/Python APIs.
MCP Servers
MCP (Model Context Protocol) servers extend agent capabilities:
Tool Selection with MCP
Middleware Configuration
Middleware extends agent behavior through a pluggable stack:
Mesh Configuration
Enable cross-machine collaboration:
Remote Agents
Define agents running on remote mesh nodes:
Sessions Database
Agent and profile TOML configs do not select database paths. A process uses one shared SQLite sessions database for the root agent and all profiles.
Database path precedence:
qmtcode --db <path>QMT_SESSIONS_DBwhen set to a non-empty value- Default
<QMT_CONFIG_DIR or QMT_HOME or ~/.qmt>/sessions.db
Programmatic builders may still call .db(...) as an explicit runtime override.
Run leases
While a local session run is in progress, the process holds an exclusive OS file lock (a run lease) on
<db-dir>/<db-stem>.run-leases/<session-id>.lock, e.g. ~/.qmt/sessions.run-leases/. The directory sits next to the
sessions database, so a separate --db gets separate leases.
- The operating system releases the lease when the process exits, including a crash or kill. This works the same on Linux, macOS and Windows.
- If a process dies mid-run, the session journal keeps a
run_startedwithout arun_completed. The next process that loads, cancels or stops that session sees the free lease and recordsrun_completedwith outcomeinterrupted, so the session no longer shows as running. - A prompt sent to a session whose lease is held by another process fails with
session is running in another process. A lease held only for a moment (while another process reconciles or deletes the session) delays the prompt briefly instead. Queued prompts of one process keep the lease between turns. - Processes that take no lease (QueryMT versions before run leases, or a run that could not take one) are not
visible to others: loading such a session elsewhere marks its live run
interrupted. Restart running instances when upgrading. - The lock files are empty and are kept after a run. Deleting a session removes its file when it is free.
- Leases are per machine. They are not reliable on network filesystems (NFS/SMB); keep the sessions database on a local disk. If the lease cannot be taken for any other I/O reason, the run proceeds without one.
- Sessions hosted on a remote node are not reconciled locally; the host closes its own runs.
Multi-Agent (Quorum) Configuration
For planner-delegate workflows:
Environment Variable Interpolation
Configuration supports environment variable interpolation:
Supported syntax:
- ${VAR} - Required variable
- ${VAR:-default} - Optional with default value
Configuration Validation
The configuration system validates: - Unique MCP server names - Valid tool names (built-in or from MCP servers) - Mesh peer references - System prompt template syntax - Required fields (provider, model)
Example Configurations
See the examples/confs/ directory for complete examples:
- single_coder.toml - Single coder agent
- coder_agent.toml - Coder agent with full features
- multi_agent.toml - Planner-delegate configuration
Profiles Configuration
Profiles allow you to save and switch between different agent configurations.
Profile Metadata
Add optional profile metadata to any configuration:
Profile Storage
Profiles can be stored in:
- User profiles (global):
~/.qmt/profiles/ - Project profiles (team-shared):
.qmt/profiles/ - Embedded profiles: Built-in with QueryMT
Using Profiles
Profile Configuration Examples
Minimal profile:
Full profile with metadata:
For complete profiles documentation, see Profiles Guide.
Slash Commands Configuration
Slash commands extend the CLI with custom functionality.
Command Locations
- User commands (global):
~/.qmt/commands/ - Project commands (team-shared):
.qmt/commands/
Command File Format
Commands are markdown files with optional YAML frontmatter:
Built-in Commands
QueryMT includes several built-in commands:
/help [command]- Show help information/mcp <subcommand>- Manage MCP servers/clear- Clear screen/exit- Exit application
Using Slash Commands
For complete slash commands documentation, see Slash Commands Guide.
Tool Argument Handling
Builtin tool parameters use snake_case names everywhere. The edit tools were the
only exception and were renamed in a single release:
| Tool | Canonical parameters |
|---|---|
edit |
file_path, old_string, new_string, replace_all |
multiedit |
file_path, edits[] of old_string, new_string, replace_all |
replace_symbol |
replacements[] of path, symbol, kind, occurrence, expected_hash, new_text; root |
Permanent aliases. The previous camelCase names (filePath, oldString,
newString, replaceAll, newText, expectedHash) and the short forms old_str /
new_str are still accepted, at the top level and inside edits / replacements
items, and are renamed to the canonical names before the call is processed. Aliases
are never advertised to the model and exist only for builtin tools: MCP and provider
tools receive their keys unchanged. Sending two spellings of one parameter (for
example new_string and newString) is rejected, even when the values are equal.
Closed schemas. Every builtin object schema sets additionalProperties: false, so
an unknown key fails validation instead of being ignored.
Unambiguous shape repairs. Before validation the schema is used to repair
mistakes that have one reading: a JSON string where an array or object is expected, an
integer sent as a string ("466, "), a single string where an array of strings is
expected, and a single edit or replacement sent without its edits / replacements
array. Broken JSON, string-typed content (such as edit text that happens to contain
JSON) and union-typed values are never modified.
search_text.exclude accepts either one glob string or an array of globs. A
question header longer than 12 characters is accepted and shortened to its first 12
Unicode scalar values before it is shown.
Raw and effective arguments
Every tool call has two argument representations with separate owners:
| Representation | What it is | Consumed by |
|---|---|---|
| Raw | The argument text exactly as the model emitted it (aliases, stringified containers, odd whitespace). Never rewritten. | Stored assistant output/history, provider replay on the next request, diagnostics. |
| Effective | Normalised, hook-adjusted and validated arguments of the prepared call. | pre_tool_use hooks (the normalised input), validation, file-access scheduling, middleware review (ParallelEditGuard), permission checks, tool invocation, snapshots, ToolCallStart events, progress records, post_tool_use hooks, and the tool_arguments stored on tool results. |
A repair therefore never rewrites history: the assistant message keeps what the model sent, while the matching tool result records what actually ran, including a target changed by a hook.
Preparation order
Each call is prepared once, in model order, and the prepared call (not the raw text) is what gets scheduled and executed:
- Reject invalid outer input (see Invalid outer input). No hook, permission check or tool sees such a call.
- Normalise the raw arguments (aliases, shape repairs). Conflicting spellings reject the call before any hook runs.
- Run
pre_tool_usehooks once on the normalised input. A hookupdated_inputis normalised the same way; a hook block wins over a conflict inside its replacement. - Validate the effective arguments against the tool schema.
- Declare the call's file access from the effective arguments.
- Middleware reviews the prepared batch (
on_prepared_tool_calls) and may reject calls, for exampleParallelEditGuardindenymode. - Conflict-aware waves are planned from the declared accesses and executed.
Preparation happens one execution segment at a time. A segment is a run of parallel-safe calls, or a single stateful/clarification barrier call. Calls after a barrier are prepared only after it finished, so their hooks see its effects (for example an updated task state). Calls skipped by cancellation or by a clarification answer are never prepared: their hooks do not run and they receive a synthetic result in model order. Every call ends with exactly one result.
Invalid outer input
For every provider, a call whose raw arguments are malformed JSON, are not a JSON
object, or were marked invalid by the provider is never executed. It is rejected
before hooks, permission checks and invocation, and receives exactly one error result
whose text is {"INVALID_JSON": "<raw input>"}. The raw input is cut to 2,000 Unicode
scalar values. Invalid input never becomes an executable {}.
The Anthropic provider marks a streamed tool call invalid when its completed buffer is
not a JSON object, and when max_tokens interrupts the block, even if the partial
buffer happens to parse. Each interrupted block completes exactly once, before the
response terminates. A block that finished normally before the limit is not
invalidated, and a block with no input deltas is the valid zero-argument call {}. The
marker travels on the canonical function-call item and is carried onto the prepared
call; it is not inferred from the argument text.
This is different from an unrepaired value inside a valid object:
The rejected call keeps its raw arguments in stored assistant history, and the tool result records them as emitted (there are no effective arguments to record).
Anthropic history replay
Anthropic requires tool_use.input to be an object. When an assistant tool call whose
stored arguments are not a JSON object is replayed, the provider sends input: {} and
logs a warning containing the call ID (never the argument text). That {} is a protocol
placeholder only: stored history keeps the raw arguments, the matching error result
stays in place, and the placeholder is never executed.
New Tools Reference
QueryMT includes several new code intelligence tools:
Code Structure Tools
index
Produce a compact structural skeleton of source files:
Returns: - Imports, types, classes, traits, impls, functions, tests - Line ranges for each item - Supports Rust, Python, TypeScript, JavaScript, Go, Java, C, C++
get_symbol
Read structured AST symbols from source files:
Parameters:
- path: File path
- symbol: Symbol name or qualified name
- kind: Symbol kind filter (function, method, class, struct, enum, trait, impl, type, const, module, test, any)
- occurrence: 0-based occurrence when multiple symbols match
- context_lines: Number of surrounding lines to include
get_function
Read one or more functions from source files by name:
Returns: - Line-numbered function bodies - Digest metadata - Context lines (configurable)
replace_symbol
Replace entire symbol bodies using AST byte ranges:
Features: - AST-aware replacement - Resolves all replacements before writing - Rejects overlapping replacements - Rejects stale writes (hash mismatch)
find_symbol_references
Find references to symbols across the codebase:
Returns: - All references to the symbol - File paths and line numbers - Reference context
Tool Configuration
Tools are configured in the [agent] section:
Tool Permissions
Configure which tools are mutating:
A permission-required tool call that no cached choice, tool policy or hook decides waits for an explicit user answer, delivered as an ACP session/request_permission request. It is never auto-granted, including when no client is attached. Unattended runs (schedules, headless) must restrict tools / mutating_tools or add permission_request hooks, or they pause at the first unanswered permission. See Session Interactions for the full lifecycle and the all-nodes-upgrade requirement (RemoteNodeUpgradeRequired).
Scheduled Tasks Configuration
QueryMT supports scheduled tasks for autonomous recurring work. Schedules are created at runtime with the querymt/schedules/create ACP extension, not through static TOML configuration. The embedded dashboard discovers schedule capabilities through ACP.
Schedule Types
Interval Schedules
Run tasks at fixed intervals. Trigger JSON format:
Event-Driven Schedules
Run tasks when accumulated events meet a threshold. Trigger JSON format:
One-Time Schedules
Fire exactly once at a specified time. Trigger JSON format:
Creating Schedules
Create schedules with the querymt/schedules/create ACP extension:
Example Configurations for Scheduled Agents
See examples/confs/watchdog.toml, examples/confs/standup_bot.toml, and examples/confs/research_journal.toml for agent configurations designed for scheduled use. These agents are configured with appropriate execution limits for autonomous scheduled cycles.
VS Code / Language Intelligence
QueryMT can provide language intelligence (LSP-like features) when connected to a VS Code client. This is not configured via TOML; instead, the VS Code extension connects to QueryMT via ACP and provides workspace query support for tools like language_query.
The language_query tool is available in the built-in tools list and can query the connected editor for:
- Hover information
- Go-to-definition
- Find references
- Completions
This requires a VS Code extension that implements the workspace query bridge.
Migration Notes
From Old Config Format
If you have old configurations, note these changes:
- system now supports file references and arrays
- execution section is nested under agent/planner/delegate
- Middleware uses type field instead of direct fields
- Mesh configuration moved to top-level [mesh] section
- Profiles added with [profile] section
- Slash commands stored in .qmt/commands/
- New tools: index, get_symbol, get_function, replace_symbol, find_symbol_references
- Scheduled tasks created via ACP extensions, not TOML config
New Features Since Last Documentation Update
- Profiles: Save and switch between configurations
- Slash Commands: Custom commands via markdown files
- Internet Mesh: iroh transport with invite tokens
- Remote Sessions: Forking, resuming, recovery
- Code Intelligence Tools: AST-aware code analysis
- Scheduled Tasks: Autonomous recurring work via ACP extensions
- Language Intelligence: VS Code integration via
language_querytool - Streaming Stability: Robust stream handling with reconnection
- Multi-Transport: LAN + Internet mesh simultaneously
Related Documentation
- Overview - Architecture and concepts
- Mesh Networking - Cross-machine collaboration
- Profiles - Configuration profiles
- Slash Commands - Custom commands
- Delegation - Multi-agent configuration
- Middleware - Processing pipeline
- Examples - Configuration examples
- API Reference - Rust API documentation