Kucatoo-Code · Wiki

Tool System

Everything an agent can do goes through the tool system: a central registry of functions with JSON-Schema specs, an executor that enforces mode/confirmation/rate-limit gates, and two pre-registered tool sets — 6 built-in tools plus 46 ported tools. The system plugs into the harness via harness.use(ToolSystem()) (model_harness/tools/system.py:46).

Architecture

flowchart LR
  Agent[BaseAgent] -->|execute_tool name args mode confirm| TS[ToolSystem]
  TS --> Reg[ToolRegistry]
  TS --> Ex[ToolExecutor]
  Ex --> ModeGate[Mode gate]
  ModeGate --> Policy[Policy hook]
  Policy --> Confirm[Confirmation gate]
  Confirm --> Rate[Rate limit]
  Rate --> Run[Run with timeout and memory cap]
  Run --> Result[ToolExecutionResult]
  Reg -.registers.-> Builtins[6 builtin tools]
  Reg -.registers.-> Ported[46 ported tools]
  Reg -.bridges.-> MCP[MCP servers]

read_only vs requires_confirmation

Two independent flags control what a tool may do:

Enforcement by mode (model_harness/agents/modes.py):

Mode Policy
EXPLORE read-only tools only, except scoped writes into docs/explore/
PLAN read-only tools only, except scoped writes into docs/plan/; ask_user is exposed
WRITE_TEST all tools; write/execute tools still confirmation-gated unless auto-confirm is on
WRITE_NO_TEST like WRITE_TEST, but the prompt tells the model not to run tests/validators/builds

The executor is the enforcement point (executor.py:146): in a read-only mode, a non-read-only tool is rejected with a structured error — unless the mode policy declares scoped_write_dirs AND the tool is in the vetted _SCOPED_WRITE_TOOLS set (write_file, append_to_file, insert_lines, replace_in_file, move_file, copy_file, apply_diff, edit_file_line, remove_line_rangeexecutor.py:54) AND every recognized path argument resolves inside a scoped directory. Tools without a caller-supplied path (execute_python, run_command, git mutations, snapshot_file, generate_image) stay fully blocked. The gate fails closed on any ambiguity (executor.py:337).

An optional policy_hook(tool, arguments) -> Optional[str] is consulted between the mode gate and the confirmation gate; a non-empty return vetoes the call, and hook exceptions fail open (executor.py:159).

On the agent side, BaseAgent (model_harness/agents/base.py) passes confirm=auto_confirm_tools (default False) and mode=self.mode into execute_tool (base.py:1270). When a call comes back confirmed=False and a confirmation_handler is installed by the web layer, the agent asks the user and re-executes with confirm=True on approval (base.py:1283). The mode's system_prompt_addendum is appended to the system message so the model knows its constraints.

Path-traversal safety

All filesystem tools resolve paths through _resolve_path() (builtin.py:52; ported tools use the mirrored helper in ported/common.py):

  1. The workspace root is: request-scoped override (guest sandbox) → explicit WORKSPACE_ROOTPath.cwd() dynamically (builtin.py:34).
  2. Relative paths resolve against the workspace root; absolute paths must already be inside it.
  3. resolved.relative_to(workspace) failing raises PathTraversalError (dtos.py:75, code PATH_TRAVERSAL).
  4. The executor deliberately re-raises PathTraversalError instead of converting it to a tool error (executor.py:255) — a workspace escape is a security error that must propagate.

Built-in tools

Registered by register_builtin_tools() (builtin.py:200). All are path-traversal safe.

ask_user (schema only)

ask_user is not in the registry and never executes in the sandbox. Only its ToolSpec exists (ASK_USER_TOOL_SPEC, builtin.py:158), with question, optional choices, and multi parameters. BaseAgent appends the schema whenever a question_handler is installed (web-driven runs, all modes — base.py:662) and intercepts calls to route them through the handler (base.py:1255), which the web layer turns into an SSE question event plus a wait for the user's answer. Without a handler the tool reports itself unavailable.

Ported tools (46)

register_ported_tools() (ported/__init__.py:48) registers 46 tools adapted from the Kucatoo source app — plain synchronous functions that run in the executor's thread pool. Categories:

Module Count Tools Flags
fileops.py 10 read_file_lines, find_files, file_tree, file_exists, move_file, copy_file, delete_file, append_to_file, insert_lines, replace_in_file 4 read-only; 6 confirmation
editing.py 5 apply_diff, edit_file_line, remove_line_range, compare_file_content, snapshot_file compare is read-only; 4 confirmation
gitops.py 9 git_status, git_diff, git_log, git_branch; git_add, git_commit, git_create_branch, git_snapshot, git_revert_snapshot 4 read-only; 5 confirmation
execution.py 6 run_command, run_script, run_python_script, run_tests; detect_shell, check_permissions 2 read-only; 4 confirmation
validation.py 4 validate_python_syntax, check_structure, validate_code_quality, run_linter all read-only
search.py 5 grep_search, find_definition, find_references, analyze_stacktrace, detect_orphaned_code all read-only
envdetect.py 2 detect_package_manager, detect_tech_stack all read-only
imagegen.py 2 generate_image, edit_image (DashScope qwen-image-*) confirmation
model_harness/lsp/tools.py 3 lsp_definition, lsp_references, lsp_diagnostics all read-only; graceful "Error:" strings when no server binary is installed

videogen (MiniMax video) lives in the ported package but is not an agent tool — renders take minutes; it is the web Video page entry point (ported/__init__.py:18).

Full tool table

The table below is generated by scripts/wiki_tables.py from the live registry (builtins + ported) — do not hand-edit it.

<!-- AUTO:tools -->

Tool Read-only Needs confirmation Description
analyze_stacktrace yes no Parse a stacktrace and extract code locations. Recognizes Python traceback frames ('File "...", line N, in ...
append_to_file no yes Append content to the end of a file. Creates the file (and parent directories) if it does not exist.
apply_diff no yes Apply a unified diff (standard '@@ -a,b +c,d @@' hunks with context/'-'/'+' lines; '---'/'+++' headers opti...
check_permissions yes no Check whether a workspace path is readable/writable via os.access. If the path does not exist yet, the near...
check_structure yes no Show an AST outline of a Python file: top-level and nested classes/functions with line numbers and indentat...
compare_file_content yes no Compare proposed content with the file on disk. Reports 'identical' (no write needed) or 'differs' plus a s...
copy_file no yes Copy a file within the workspace. Creates parent directories of the destination; refuses to overwrite an ex...
delete_file no yes Delete a single file from the workspace. Refuses to delete directories.
detect_orphaned_code yes no Detect suspicious trailing fragments in a Python file — incomplete def/class blocks at EOF, syntax errors n...
detect_package_manager yes no Detect which package managers apply to the workspace: which manifest files are present (requirements.txt, p...
detect_shell yes no Report the OS platform, default shell, which shells are on PATH, and the Python version.
detect_tech_stack yes no Detect the likely languages, frameworks, ORM, and database of the workspace project. Combines manifest insp...
edit_file_line no yes Replace exactly one 1-based line of a file with new content. Safer than full rewrites for small fixes. Show...
edit_image no yes Edit an existing workspace image per a text instruction via DashScope (qwen-image-edit-plus) and save the r...
execute_python no yes Execute Python code in a restricted sandbox. No imports, no file I/O, no network access. Safe builtins only.
file_exists yes no Check whether a path exists in the workspace, and report whether it is a file or directory and its size in ...
file_tree yes no Show an indented ASCII tree of directories and files under a directory, capped by max_depth. Skips noisy di...
find_definition yes no Find where a symbol is defined in the workspace (lean local replacement for an LSP resolve-symbol call). Pa...
find_files yes no Recursively find files matching a glob pattern under a directory, capped by max_depth. Skips noisy dirs (.g...
find_references yes no Find references to a symbol in the workspace (lean local replacement for an LSP find-references call). Word...
generate_image no yes Generate an image from a text prompt via DashScope (qwen-image-max) and save it under images/ in the worksp...
git_add no yes Stage files for the next commit (git add). Paths must be inside the workspace.
git_branch yes no List local branches (current one marked with *). Set show_all=True to include remote-tracking branches. Lis...
git_commit no yes Commit staged changes with the given message. A fallback committer identity is supplied so repos without gi...
git_create_branch no yes Create a new branch. With checkout=True (default) also switch to it (git checkout -b).
git_diff yes no Show uncommitted changes (git diff). Set staged=True for staged changes, and optionally limit to a single f...
git_log yes no Show recent commit history. oneline=True gives one line per commit; otherwise includes per-commit file stat...
git_revert_snapshot no yes Hard-reset the workspace to a previous snapshot commit (git reset --hard <sha>). Uncommitted changes are di...
git_snapshot no yes Take a snapshot of the whole workspace: initializes a git repo if needed, stages everything (git add -A) an...
git_status yes no Show the working tree status of the workspace git repository, with the current branch. Use short=True for a...
grep_search yes no Search file contents with a regular expression (like grep). Searches files under a workspace directory whos...
insert_lines no yes Insert content into a file so its first line becomes the 1-based line_number. line_number may be one past t...
list_files yes no List files in a directory matching a glob pattern. Use recursive=True to search subdirectories.
lsp_definition yes no Go to the definition of an identifier via a language server (textDocument/definition). The identifier is lo...
lsp_diagnostics yes no Type-check a file via its language server by opening the buffer and collecting textDocument/publishDiagnost...
lsp_references yes no Find references to an identifier via a language server (textDocument/references). The identifier is located...
move_file no yes Move or rename a file within the workspace. Refuses to overwrite an existing destination.
read_file yes no Read the contents of a file from the workspace. If max_lines is set, returns only the first N lines.
read_file_lines yes no Read a file with a 1-based inclusive line range. Each line is prefixed with its line number. Omit end_line ...
read_pdf yes no Extract text from a PDF file in the workspace. Returns page-numbered text starting at start_page (1-based);...
remove_line_range no yes Delete an inclusive 1-based line range from a file. Reports how many lines were removed and previews the fi...
replace_in_file no yes Replace a literal string (NOT regex) in a file. Fails without writing unless the string occurs exactly expe...
run_command no yes Run a shell command in the workspace. Output is captured and returned. Dangerous commands (disk wipes, fork...
run_linter yes no Run a static analysis tool (pyflakes, flake8, pylint, or mypy) on a workspace file or directory via 'python...
run_python_script no yes Run a Python (.py) file from the workspace with the current Python interpreter and return its output.
run_script no yes Run a script file from the workspace. .sh runs via sh, .bat/.cmd via cmd.exe, .py via the current Python; o...
run_tests no yes Run pytest on a workspace path (or the whole workspace). Use pattern to select tests by name (-k). Writes n...
snapshot_file no yes Snapshot a file into the workspace's .versions/ directory with a timestamp suffix before making risky chang...
task no no Delegate a scoped subgoal to a fresh child agent and get its final answer. Use for self-contained chunks of...
use_skill no no Run a registered skill by id. Skills are reusable, versioned capabilities (code review, summarization, anal...
validate_code_quality yes no Lightweight quality gate for a Python code string: compile check, mixed tabs/spaces indentation, lines over...
validate_python_syntax yes no Validate Python syntax without executing the code. Accepts either a workspace file (filepath) or an inline ...
web_search yes no Search the web for current information. Returns top_k results with title, url, and a content snippet.
write_file no yes Write content to a file in the workspace. Creates parent directories if needed.
<!-- /AUTO:tools -->

verified against code: 2026-08-09