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
git.add Stage files Ask
git.commit Commit staged changes Ask
git.checkout Check out branch / files Ask
git.diff Show diffs Allow
git.log Commit history Allow
git.show Show a commit's details Allow
git.blame Line-by-line attribution Allow
git.stash Stash / restore work in progress Ask
git.merge Merge branches Ask
git.rebase Rebase Ask
git.worktree.create Create a worktree Ask
git.worktree.list List worktrees Allow
git.worktree.remove Remove a worktree 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 / subagents (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; stages validate_args / policy_denied / needs_approval / connect / list_tools / ok; an http / sse address pointing at this machine / the LAN gives policy_denied unless the session is unrestricted) 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 duplicate line_hashes, and emit pagination bookkeeping (next_offset, etc.) only when truncated=true.

11.3 fs.read

Arg Type Default Description
path string — Required; relative to workspace root, or an absolute path inside the workspace
mode enum lines lines / bytes
offset int 0 Starting line / byte
limit int 4096 soft Byte cap; hard cap 256 KiB
as_text bool false Force a file judged to be binary to be read as text

Encoding detection: a BOM takes priority; without one, common encodings such as GBK / GB18030 / UTF-16 are detected and decoded to UTF-8 before delivery. grep uses the same decoding path. Files judged to be binary are refused by default (override with as_text).

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)

Shell syntax supported (outside unrestricted mode too):

Syntax Rule
&& / || / ; chaining, | pipes Each segment is checked against the allowlist separately; if any segment fails, the whole command is rejected
> / >> redirection The target must land inside the workspace or an attached writable path
cd Allowed, still confined to the workspace
  • samples/ blocks execution only — reading files there, or passing them as arguments, is no longer refused.
  • Commands issued through test.run / lint.run / sast.run go through the same guardrails and the same tokeniser.
  • Path handling: absolute paths inside the workspace are judged exactly like relative ones; absolute paths are no longer refused outright.
  • The allowlist now includes the cc family (cc / gcc / clang, …): write-out channels (-o, -MF, …) are confined to the workspace, and dangerous flag prefixes are blocked.
  • Command-name normalisation (Windows): case and a .exe suffix no longer change the allowlist verdict; policy rejections carry the offending command and rule in the error.
  • Output encoding: on Windows, GBK / UTF-16 output is normalised to UTF-8 at the collection point (both fs.exec and fs.exec.tail).
  • Echo: the command echoed back in the result keeps its original quoting instead of being re-joined with spaces.
  • Windows batch files (.bat / .cmd) have dedicated argument-injection guards.
  • The working directory cannot be hijacked: a same-named file inside the workspace is never resolved as the program to run.

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, model chosen by routing strategy (see §11.12.3, §6.8.1)
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.read line 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 (24, 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 readable truncated_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

Model: chosen by the model routing strategy among enabled 澜砥 models with an API key (Best quality by default); when none is available, the current session's provider / model (injected implicitly) is used; in local mode only the session's model is used; if neither is available the call errors. Timeout and output limit follow the chosen model's configuration. Retrieved snippets are sent to the chosen model.

Returns answer + citations[] (file / start_line / end_line / name) + hit_count + model + provider + routed (whether routing chose a 澜砥 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 both plan and assess (running tests has write side-effects).

11.13.1 Self-check gate (opt-in, generalised multi-checker)

Field Scope Default Notes
Self-check gate G — Settings → Testing & 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 testgen to checks.
  • 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: judge runs 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.load first". These two introspection tools themselves always pass through the subagent 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.load names a category. Categories from MCP backends connected mid-session are admitted automatically.
  • Bypass: when there are ≤ 32 visible candidates, the whole table is admitted (subagent 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 server 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.