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 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
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.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 (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 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

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 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 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.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 (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.