Part III — Tool Catalogue
This part covers Chapters 11–14: parameter lookup for the smart-coding and security-analysis tools, external-tool-service fields, and the tool permission policy.
11. Smart-coding tools
[!ref] Full details in the User Manual, "Smart-coding tools".
11.1 Tools
| Tool | Purpose | Default permission |
|---|---|---|
fs.read |
Read file (line / byte) | Allow |
fs.write |
Overwrite whole file | Ask |
fs.patch |
Precise replace by line + verify hash | Ask |
fs.list |
List directory | Allow |
fs.glob |
Glob match filenames | Allow |
fs.grep |
Regex content search | Allow |
fs.exec |
Sync shell exec | Ask |
fs.exec.start |
Start background command; returns session_id | Ask |
fs.exec.tail |
Tail background output | Allow |
fs.exec.kill |
Kill background command | Allow |
fs.exec.list |
List current background commands | Allow |
time.now |
Current time (with timezone) | Allow |
git.status |
Repo status | Allow |
git.branch |
Create / switch branch | Ask |
git.init |
Init repo | Ask |
web.bing |
Bing search (RSS endpoint) | Allow |
web.fetch |
Fetch URL and clean to readable text | Allow |
skill.list |
List available skills | Allow |
skill.invoke |
Render and invoke a skill | Allow |
TodoWrite |
Write / update todo (≤50 entries) | Allow |
TaskWait |
Block-and-wait for background tasks / sub-agents (default 5m, max 30m; all / any) |
Allow |
SuggestTask |
The AI proposes an out-of-scope task (card in stream; doesn't interrupt) | Allow |
DismissTask |
The AI withdraws a stale suggestion | Allow |
mcp.list_servers |
List all MCP servers | Allow |
mcp.describe_server |
Detail one server (secrets masked) | Allow |
mcp.list_tools |
Tools a server exposes | Allow |
mcp.test_server |
Real-handshake probe (30s budget, 4 stages) | Allow |
mcp.add_server |
Add server (write, two-step confirm=true) |
Ask |
mcp.remove_server |
Remove server (write, two-step). The default MCP backend can now also be removed (gateway used to refuse — fixed) | Ask |
mcp.toggle_server |
Enable / disable server (write, two-step) | Ask |
mcp.import_config |
Bulk import; Claude Desktop schema supported (write, two-step) | Ask |
mcp.export_config |
Export current config (secrets masked) | Allow |
PluginSearch |
Search the plugin-marketplace catalogue (global read-only; needs no workspace context) | Allow |
PluginList |
List installed / installable plugins | Allow |
PluginInstall |
Install a plugin and activate it in the current workspace (write, two-step: returns a dry_run preview first — capability list / real MCP command lines / signature status / source provenance — and lands only with confirm=true; signature checks follow the product policy) |
Ask |
PluginUninstall |
Uninstall a plugin and clean up leftover tool config in sync (write, two-step) | Ask |
11.2 Common return fields
Read / search tools return:
| Field | Type | Description |
|---|---|---|
truncated |
bool | Whether output was capped (soft / hard) |
next_offset |
int | Next line-mode read offset |
next_byte_offset |
int | Next byte-mode read offset |
content_hash |
string | Whole-file content fingerprint (used by writes) |
line_hashes |
array | Line-level fingerprints (used by patch); deduplicated, emitted only when needed |
Slimmer results (saves tokens / quota): workspace tools return paths relative to the workspace root (
relPath), strip the root-path prefix from error strings (no leaking the absolute root), drop duplicateline_hashes, and emit pagination bookkeeping (next_offset, etc.) only whentruncated=true.
11.3 fs.read
| Arg | Type | Default | Description |
|---|---|---|---|
path |
string | — | Required; relative to workspace root |
mode |
enum | lines |
lines / bytes |
offset |
int | 0 | Starting line / byte |
limit |
int | 4096 soft | Byte cap; hard cap 256 KiB |
11.4 fs.write
| Arg | Type | Default | Description |
|---|---|---|---|
path |
string | — | Required |
content |
string | — | Required |
expected_hash |
string | — | The content_hash from the previous read; CAS to defeat concurrent overwrite |
11.5 fs.patch
| Arg | Type | Default | Description |
|---|---|---|---|
path |
string | — | Required |
start_line |
int | — | 1-based |
end_line |
int | — | 1-based, inclusive |
replacement |
string | — | New content |
verify_hashes |
array | — | The line_hashes for that range; mismatch rejects |
11.6 fs.list
| Arg | Type | Default | Description |
|---|---|---|---|
path |
string | . |
Relative to workspace root |
pattern |
string | * |
Shell glob |
include_hidden |
bool | false | Include dotfiles |
sort |
enum | name |
name / mtime / size |
limit |
int | 4096 bytes | Single-return cap |
11.7 fs.glob
| Arg | Type | Default | Description |
|---|---|---|---|
pattern |
string | — | Glob expression |
path |
string | . |
Relative to workspace root |
sort |
enum | mtime |
mtime / name |
| Auto-skip | — | .git/ node_modules/ dist/ |
Not configurable |
11.8 fs.grep
| Arg | Type | Default | Description |
|---|---|---|---|
pattern |
string | — | RE2 regex |
path |
string | . |
Relative to workspace root |
path_glob |
string | **/* |
Filename filter |
case |
enum | smart |
sensitive / insensitive / smart |
context |
int | 0 | Context lines |
include_binary |
bool | false | Default heuristic skips binaries |
11.9 fs.exec / fs.exec.start
| Arg | Type | Default | Description |
|---|---|---|---|
cmd |
string | — | Required |
cwd |
string | Workspace root | Relative path |
timeout_seconds |
int | 120 | Kill on timeout |
env |
object | — | Append env |
stdin |
string | — | Optional |
output_byte_limit |
int | 4096 / 256 KiB | Soft / hard cap (per of stdout, stderr) |
11.10 fs.exec.tail / .kill / .list
| Tool | Args | Description |
|---|---|---|
fs.exec.tail |
session_id, stream (stdout default / stderr), byte_offset?, byte_limit? (default 4096, hard cap 256 KiB) |
Resume reading output from a byte offset; returns status / exit_code / buffer_truncated / next_byte_offset |
fs.exec.kill |
session_id, grace_seconds? |
Terminate the session; grace_seconds sends SIGTERM, waits N seconds, then SIGKILL — 0 = straight to SIGKILL (ignored on Windows). Unix kills the whole process group, Windows kills only the head process |
fs.exec.list |
none | List current background sessions |
Local background-session caps: at most 16 concurrent; per-session disk log 256 MiB (overflow drops the tail); logs remain tailable after the process exits; auto-GC after 1 hour; sessions end with the Interpreter's lifecycle.
SSH remote background sessions are not subject to the above: state and logs live on the remote under
<root>/.avlcode/sessions/, logs are complete files (no 256 MiB ring-buffer tail loss), and they survive reconnects and app restarts (see §22.4).
11.11 web.bing / web.fetch
| Tool | Args | Description |
|---|---|---|
web.bing |
query, top_k (default 5) |
Bing RSS search; returns title / snippet / URL |
web.fetch |
url, format (md / txt / html) |
Fetch and clean |
11.12 code.* — Code-intelligence toolset (LSP-based)
| Tool | Args | Description |
|---|---|---|
code.definition |
path, symbol or line/character |
Jump to a symbol's definition |
code.references |
path, symbol or line/character, include_declaration (default false) |
Find every reference / call site |
code.hover |
path, line, character |
Symbol's type / signature / docs |
code.symbols |
path |
File symbol outline |
code.workspace_symbols |
query |
Workspace-wide symbol search by name |
code.diagnostics |
path (may be empty) |
Compile errors / warnings; empty path returns workspace aggregate |
code.call_hierarchy |
path, symbol or line/character, direction (incoming / outgoing) |
Call graph |
code.repo_map |
— | Project skeleton (file tree + top-level symbols per file), token-friendly |
code.rename |
path, symbol or line/character, new_name |
Cross-file safe rename (writes to disk) |
code.code_action |
path, line, character, apply_title (optional) |
Without title: list actions; with title: apply that quick fix (writes) |
code.lsp_status |
— | Live LSP server pool: running servers / project root / liveness / online·idle seconds / supported languages |
code.search |
query (req), limit (def 20), path, refresh (def false), expand (def false) |
Non-vector whole-repo RAG search (see §11.12.3) |
code.ask |
question (req), limit (def 12), path |
Whole-repo RAG Q&A, reuses the session model (see §11.12.3) |
code.implementation |
path, symbol or line/character |
Jump from an interface / abstract method to its implementations (LSP implementation) |
code.type_definition |
path, symbol or line/character |
Jump from a variable / expression to its type declaration (LSP typeDefinition) |
code.document_highlight |
path, symbol or line/character |
Every read / write / reference of a symbol within the current file — lighter than a whole-repo references lookup |
code.completion |
path, line, character |
Completion candidates at that cursor position |
code.signature_help |
path, line, character |
Parameter signature of a call plus the currently highlighted argument (put the cursor inside the call parentheses) |
code.formatting |
path, tab_size (def 4), use_tabs (def false) |
Format the whole file per LSP and write it to disk; no write when nothing changes |
Position parameters are 1-based (matching
fs.readline mode /cat -n); converted to 0-based at the interpret layer before LSP.
Capability degradation: optional capabilities (implementation / type_definition / document_highlight / completion / signature_help / formatting, etc.) aren't implemented by every language server. Support is decided by the actual response, not predicted from the server's declaration (which avoids false rejections when a declaration is missing); once judged unsupported, the result is cached across sessions so the same server isn't probed again.
11.12.1 Built-in languages (22, by ID)
go · ts · py · c (cpp) · rust · java · deno · eslint (js linting) · lua · bash · yaml · php · ruby · vue · zig · dart · kotlin · clojure · elixir · haskell · fsharp · csharp · gleam · astro
Each language binds to an LSP command (gopls / typescript-language-server / pyright-langserver / clangd / rust-analyzer / jdtls / …); missing servers auto-download on demand (go install / npm etc.) with install-progress display.
11.12.2 User config file lsp.yaml / lsp.json
In workspace .avlcode/ or ~/.avlcode/, the first existing of lsp.yaml > lsp.yml > lsp.json wins:
lsp:
rust:
disabled: true # disable
go:
cmd: gopls # override launch command
args: ["-rpc.trace"]
root_markers: ["go.mod", "go.work"]
custom_lang: # add a custom server
extensions: [".myx"]
cmd: my-langserver
install_via: npm
install_pkgs: [my-langserver]
Hot reload: mtime/size changes re-read automatically — no workspace restart needed. Crashed server processes / dropped SSH sessions auto-restart.
11.12.3 Whole-repo RAG search and Q&A (code.search / code.ask)
Non-vector (zero-embedding) symbol-level whole-repo search: BM25 + identifier tokenization (camelCase / snake_case / kebab-case) + CJK bigram tokenization (so Chinese comments and Chinese questions match too), local and offline. The index lives in <base>/.avlcode/rag/symbols.jsonl (in-memory only for remote workspaces); after the first build it incrementally syncs by file mtime (edit / add / delete). Only definition-kind symbols are indexed (functions / methods / types / interfaces / constants, etc.).
The index covers at most 4000 files (not configurable). Beyond that the result reports the shortfall honestly rather than truncating silently: it carries
index_covers_all_files=false,files_not_indexed(how many files were left out of the index) and a readabletruncated_hint, so you can tell whether "no hits" means it really isn't there or simply wasn't covered.
code.search parameters
| Param | Type | Default | Notes |
|---|---|---|---|
query |
string | — | required, natural language / keyword / symbol name |
limit |
int | 20 | max hits returned |
path |
string | workspace root | focus a subdirectory |
refresh |
bool | false | force a full index rebuild |
expand |
bool | false | structure rerank: run LSP call-hierarchy on top hits — called more = more central = ranked higher (more accurate, slower) |
Returns hits[] (file / start_line / end_line / name / kind / score / why[] (matched keywords) / optional container·signature), count, indexed_symbols, indexed_files; a hint when empty.
code.ask parameters
| Param | Type | Default | Notes |
|---|---|---|---|
question |
string | — | required, natural-language question |
limit |
int | 12 | retrieval snippets fed into synthesis |
path |
string | workspace root | focus a subdirectory |
Reuses the current session's provider / model (injected implicitly; falls back to AVL-Zero if unset). Returns answer + citations[] (file / start_line / end_line / name) + hit_count + model; says so plainly when nothing is found, never fabricates. Applies the structure-aware smart rerank to expanded retrieval by default (no explicit expand needed).
Caps: index files ≤ 4000, full-build timeout 120 s, ≤ 400 symbols / ≤ 4 MiB per file; structure rerank takes the top 8 hits. The incremental-refresh scope is corrected (no over-/under-refresh after file changes).
11.13 test.run — Test runner + structured failure feedback
| Field | Type | Description |
|---|---|---|
framework |
string | Optional; go / pytest / cargo / node (vitest / jest); empty = auto-detect |
path |
string | Optional; scope (Go package pattern ./pkg/..., pytest dir / file, cargo package name) |
command |
string | Optional; fully override the test command (e.g. go test -run TestFoo ./pkg) |
timeout_sec |
int | Default 300s |
Returns: failures[] (up to 50 {test, file, line, message}) + a small raw tail. Unknown frameworks degrade to exit code + tail. Disabled in plan (running tests has write side-effects); available in assess, so the acceptance stage can actually run the tests.
11.13.1 Self-check gate (opt-in, generalised multi-checker)
| Field | Scope | Default | Notes |
|---|---|---|---|
| Self-check gate | G | — | Settings → Tests & Checks tab configures the global default (~/.config/avlcode/checkgate-default.yaml) |
| Self-check gate | W | Off | Workspace .avlcode/testgate.yaml; default for new sessions |
| Self-check gate | S | Inherit W | Session menu's per-check toggle list; shows actually-in-effect state |
| Only after edits | — | Yes | Turns with no file changes skip the pass |
| Max consecutive injections | — | 3 | When hit, gate disengages |
testgate.yaml schema:
enabled: true
checks: # list of checkers (any combination)
- name: test # test | diagnostics | lint | sast
mode: block # block | report
submode: changed # test: changed | full
scope: changed # changed | workspace
- name: lint
mode: block
submode: strict # lint: strict | lenient
linters: [errcheck, govet] # subset (optional)
- name: sast
mode: report
submode: quick # sast: quick | deep
config: .semgrep.yml # offline rules (optional)
modes: # per-work-mode override
plan: { enabled: false }
prepare: { enabled: false }
11.13.2 CheckSpec fields
| Field | Type | Description |
|---|---|---|
name |
enum | test / diagnostics / lint / sast / testgen / judge |
mode |
enum | block (default, inject + force fix) / report (notify only, no block) |
submode |
string | test: changed / full; lint: strict / lenient; sast: quick / deep |
scope |
enum | changed (default, files changed this turn) / workspace (whole repo) |
path |
string | Optional scope restriction |
linters |
array | lint subset (optional) |
config |
string | Custom config path (e.g. .semgrep.yml for sast) |
timeout_sec |
int | Per-checker timeout |
11.13.2a testgen — Auto-add tests when edits lack them (opt-in)
- Not in the default set: you must explicitly add
testgentochecks. - Covered languages: Go / Python / JavaScript / TypeScript; other extensions (
.c/.java, …) aren't judged. - Skips test files themselves and generated artifacts: avoids "writing tests for tests" / "writing tests for
.pb.go". - Existence check via the zMCP gateway (
fs.glob) — works correctly on SSH remote. - Shares the 3-injection hard cap (
MaxTestGateRetries): worst-case mis-fire is 3 rounds before the gate disengages.
11.13.2b judge — LLM end-of-turn self-review (opt-in, defaults to report)
- Independent fresh-context model call (reusing
agentFacade.CompactSummaryStream); carries none of the agent's own conversation history, removing self-justification bias. - Looks at: this turn's goal + diff — catches logic / semantic / security-intent issues machine checks miss.
- Few-shot examples + this turn's diagnostics injected as prompt background — sharper judgment, fewer false positives.
- Gating:
judgeruns after every cheap checker and only when all block-mode checkers are green. - Model gibberish / dirty JSON / timeout → non-authoritative pass-through, never false-blocks.
- Return shape:
{ok: bool, issues: [{file, line, severity, confidence, message}]}—severity ∈ error / warning / info,confidence ∈ 0..1. Block-mode confidence / severity thresholds are planned for Phase 2.
11.13.3 lint.run — Static linting (read-only)
| Field | Type | Description |
|---|---|---|
linter |
string | golangci-lint / eslint / ruff; empty = auto-detect (go.mod → golangci-lint / .eslintrc·eslint.config → eslint / pyproject.toml·ruff.toml → ruff) |
path |
string | Scope (directory / file / Go package pattern ./...) |
linters |
array | Subset (e.g. errcheck / govet for golangci) |
submode |
string | strict (warnings count as red) / lenient |
config |
string | Custom config file path |
command |
string | Fully override the command |
timeout_sec |
int | Default 180 |
Returns: findings[] ({file, line, rule, severity, message}), same shape as test.run. golangci-lint v1 / v2 JSON output flags adapt automatically. Read-only; available in plan / assess.
11.13.4 sast.run — Security static analysis (read-only)
| Field | Type | Description |
|---|---|---|
path |
string | Scope |
submode |
string | quick (caps large files for speed) / deep (full) |
config |
string | Rules; empty = --config auto (requires network); offline, point to local .semgrep.yml |
command |
string | Fully override the command |
timeout_sec |
int | Default 240 |
Returns: findings[] same shape. Backend: semgrep. Read-only; available in plan / assess.
11.14 tools.list / tools.describe / tools.load — Tool introspection and on-demand loading
| Tool | Args | Description |
|---|---|---|
tools.list |
prefix (optional) |
List the tools callable in this session (name + description); filter by namespace |
tools.describe |
name (required) |
Full schema (description + parameter definitions) for a given tool |
tools.load |
category name | Load a category of tools; with no argument, returns the category directory (one-line capability blurb + tool names per category) |
Introspection results are trimmed to what is actually available in this session (affected by the three-state tool permissions and by category lazy loading); the returned notes point out that "not in the list ≠ doesn't exist — try
tools.loadfirst". These two introspection tools themselves always pass through the sub-agent allowlist, but their output is still trimmed to that allowlist, and they can't override a user-configured deny list.
11.14.1 Tool category lazy loading
On by default (Settings.ToolLazyLoad, since schema v9). The switch lives in the agent manager → "Configure tools" tab → "Tool category lazy loading", not on the Settings page.
- Always-resident categories:
fs(read/write / glob / grep / exec),tools(list / describe / load),agent(delegation + EnterPlanMode / ExitPlanMode / TodoWrite). - 16 loadable categories:
code/git/sec/vt/sbom/mcp/web/skill/test/lint/sast/market/plugin/gh/sys/time. - Loading paths: ① implicit — categories are preloaded from keywords in each new user message (English and Chinese keyword tables); ② explicit —
tools.loadnames a category. Categories from MCP backends connected mid-session are admitted automatically. - Bypass: when there are ≤ 32 visible candidates, the whole table is admitted (sub-agent allowlist mode usually takes this path).
- When enabled, the system prompt carries a note telling the assistant the tool list is deliberately trimmed and can be extended on demand.
- Each MCP service can be configured individually for lazy loading (
Settings.MCPLazyLoad, defaults to following the global switch) — see §13.1.
11.15 Python venv auto-detection
fs.exec / fs.exec.start follow the workspace virtual environment automatically when running Python commands:
| Source | Probed path |
|---|---|
| Standard venv | <workspace>/.venv / <workspace>/venv |
| conda | bin/python under the env directory (incl. Windows Scripts/python.exe) |
| poetry | poetry env info -p (out-of-tree envs supported) |
| pipenv | pipenv --venv |
Mechanism: rewrites the first command to the absolute path inside the venv and injects VIRTUAL_ENV / PATH. Out-of-tree discoveries cache for 5 min / 15s probe timeout. Global disable: AVLCODE_DISABLE_VENV_AUTODETECT=1.
pyright(code.*) is venv-aware too — consistent across local + SSH remote.Exception: background commands on an SSH remote (
fs.exec.start) are not venv-aware — venv detection reads the local machine's directory layout, so on a remote it would resolve to the wrong, local paths. Name the interpreter explicitly when running Python background tasks on a remote.
