Tool Inventory · Two-Layer Architecture × Language Intelligence

CodePapr exposes 25 merged tools to the LLM (graph is now UI-only), routed by dispatchers to 61 fine-grained workspace_* tools (hidden from the LLM), ultimately landing on the Tauri / Rust backend. Code intelligence (the lsp tool's 9 navigation actions) is wired to an LSP → AST project-graph fallback, tagged with source/confidence for precision; list(action: overview) provides an AST project-structure overview. File read/write/edit (read / write / edit / patch) do not yet leverage language intelligence. Click any entry to expand its dispatch chain and integration status.

LSP-backed AST-backed LSP + AST Plain text Multimodal
25
LLM-visible merged tools
graph now UI-only
61
Hidden fine-grained tools
workspace_* / shell_* / browser_*
15
Real LSP languages
Rust symbol_provider.rs
17
AST languages
tree-sitter
11
regex fallback languages
0
read/write/edit/patch
tools wired to LSP/AST
01

File Ops File Operations

read / write / edit / patchgrep / glob / listAll plain text
Refactor targetNot yet wired to LSP/AST
Read/Write/Edit Direct file-content ops · all plain-text semantics
READ
read→ workspace_read_file · workspaceTools.ts:1913
invoke read_text_fileRust read.rs:42
Plain text
Reads the raw contents of a project file. Supports startLine/endLine line ranges, an aroundLine window, and maxBytes (raw read defaults to 500KB). Completely unaware of LSP/AST; returns plain text, clamped by the truncation layer before entering context.
Dispatch: readworkspace_read_fileinvoke('read_text_file'). Output passes through truncateToolOutput: >30k chars middle-truncated / >50k offloaded to disk + 2k preview / 150k hard cap. No symbol outline, no owning-file structure info.
WRITE
write→ workspace_write_file · workspaceTools.ts:1957
invoke write_text_fileeditHistory.recordnotifyWorkspaceMutation
Plain text
Creates or fully overwrites a file. After writing, records edit history and broadcasts the mutation. Runs no diagnostics after writing—syntax errors only surface when the LLM remembers to call diagnostics itself.
Dispatch: writeworkspace_write_fileinvoke('write_text_file'). Post-write notifyWorkspaceMutation([path]) (a natural hook for cache invalidation). No AST parse validation, no LSP diagnostic feedback.
EDIT
edit→ workspace_apply_patch · workspaceTools.ts:3271
applySearchReplacePatchsearchReplaceDiff.ts
Plain text
Precise single-file SEARCH/REPLACE. Pure literal String.indexOf matching (after CRLF→LF normalization), zero fuzzy. Re-reads the source independently of read (maxBytes 20MB), then re-reads after writing to verify consistency.
Matching semantics: search must match byte-for-byte; expectedOccurrences validates the count; multiple matches require replaceAll. When the same text appears in several functions, you can only guess by lengthening search or via expectedOccurrences—no symbol anchor available. No diagnostic feedback after the change.
PATCH
patch→ workspace_apply_diff · workspaceTools.ts:3325
applySearchReplaceDiffmulti-file atomic
Plain text
Multi-file atomic SEARCH/REPLACE: all patches are written together only after every one matches exactly; any failure rolls back. Matching mechanism is identical to edit (pure literal), only adding cross-file atomicity.
Dispatch: patchworkspace_apply_diff. Re-reads source per file → applySearchReplaceDiff applies sequentially → writes per file + re-read verification → batch notifyWorkspaceMutation.
Search Lexical-level search · complements the semantic symbol index (graph lookup)
GREP
grep→ workspace_search_text · workspaceTools.ts:2267
isRegexp:truesmart-case
Plain text
Searches file contents by regex, returning match positions and context. contextLines defaults to 0, max 8; maxResults defaults to 80. Purely lexical; does not annotate which symbol a hit belongs to.
Dispatch: grepworkspace_search_text (forces isRegexp:true). Semantic-level "find symbol" should go through graph action=lookup.
GLOB
glob→ workspace_search_files · workspaceTools.ts:2289
globToRegexregisterSharedWorkspaceTools.ts:216
Plain text
Searches file names by glob pattern (e.g. **/*.test.ts). The dispatcher first converts the glob to a regex, then hands it to workspace_search_files.
Dispatch: globglobToRegex()workspace_search_files (isRegexp:true).
LIST
list→ workspace_list_files / workspace_project_graph · workspaceTools.ts:1917
action: files | overviewinvoke list_workspace_files
Text + AST
action: files (default) browses the directory tree (maxDepth defaults to 2, max 6); action: overview returns an AST project structure overview (directory tree + symbol skeleton), forwarding to workspace_project_graph(view=overview). overview is the LLM entry point for the former graph action=overview (graph is now hidden from the LLM).
Dispatch: listaction=overview ? workspace_project_graph(view=overview) : workspace_list_filesinvoke('list_workspace_files').
IMG
read_image→ workspace_read_image · workspaceTools.ts:1934
invoke read_image_filebase64
Multimodal
Reads an image (PNG/JPEG/WebP/GIF) as base64 for vision-model recognition. maxBytes defaults to 5MB. Visible to the LLM only when multimodalEnabled; otherwise hideFromLlm.
Registered at workspaceTools.ts:3517 (forwards directly to workspace_read_image); :3521 calls hideFromLlm('read_image') when not multimodal. The result carries an internal __images field, stripped by stripInternalFields on truncation.
02

Code Intelligence Code Intelligence

lsp / lsp_edit / diagnosticsgraph now UI-onlyLSP→AST degradation
Point queries wired to degradationlsp 9 actions · source/confidence
Semantic graph ProjectGraph · symbol source lsp / ast / pattern
GRAPH
graph→ workspace_project_graph etc. · workspaceTools.ts:2777 · hidden from the LLM
14 actions (UI-only)hideFromLlm:3793
UI + AST fallback
Now hidden from the LLM (UI-only). The 14 actions remain: full / overview / lookup / dependency / entrypoints / impact / implementations / smart_context + 6 analyses (dead_code / circular_deps / type_hierarchy / suggest_refactors / test_impact / generate_tests). The fine-grained handlers stay registered, serving UI panels and acting as the AST fallback backend for lsp point queries; the project structure overview is now exposed to the LLM via list(action: overview).
Build chain: list_workspace_files → per-file read_text_file → LSP documentSymbol coverage → buildWorkspaceProjectMapbuildWorkspaceProjectGraph → LSP edge enrichment. Full rebuild on every call, zero caching (hence only used as fallback/UI, not the main path). Symbols go through UnifiedSymbolDispatcher.extractSymbols (lsp→ast→regex degradation).
LSP navigation & semantic editing precise to file:line:column
LSP
lsp→ workspace_symbol_* / document_symbol / workspace_symbol / implementation / *_call_hierarchy · :3068+
9 actions (opencode naming)astFallback:2930
LSP → AST
Read-only language-service navigation and analysis, 9 actions: goToDefinition / findReferences / hover / documentSymbol / workspaceSymbol / goToImplementation / prepareCallHierarchy / incomingCalls / outgoingCalls. Each action is LSP-first; when LSP is unavailable or returns nothing it automatically degrades to the AST project graph (a graph query), with results tagged by source(lsp/ast) and confidence(high/medium/low) precision. Requires file:line (:column optional).
Dispatch: lspcreateDefaultLspHandlerworkspace_symbol_definition/references/hover/.... Each handler first calls requestWorkspace* (LSP, 30s timeout); if !available or the result is empty → astFallback (workspaceTools.ts:2930) locates the symbol via findSymbolAtPosition, then runs a graph query (lookup / changeImpact / implementations / dependency). The AST fallback is symbol-level (graph symbols have line numbers only, no column), confidence=medium.
LEDIT
lsp_edit→ rename / code_action / format · :2933 / :2954 / :3035
action: rename | code_action | format
LSP
Language-service semantic modifications: rename (applies a workspace edit), pick a code action by title/kind, batch formatting. This is the existing seed of "semantic editing", but it is completely disconnected from edit/patch.
Dispatch: lsp_editworkspace_rename_symbol / workspace_apply_code_action / workspace_format_files. rename obtains a WorkspaceEdit via LSP textDocument/rename, then persists to disk.
DIAG
diagnostics→ workspace_lsp_diagnostics / project_diagnostics · :2977 / :3396
invoke lsp_get_diagnosticsRust lsp.rs:1689
LSP
Pass relativePath to query single-file LSP diagnostics; pass project:true to run project-level lint/typecheck. A standalone tool—the LLM must remember to call it itself; it is not auto-triggered after write/edit.
Single file: invoke('lsp_get_diagnostics',{languageId}) returns diagnostics grouped by uri, matched to this file by path suffix. Whole project: iterates available provider languages and aggregates topIssues.
Hidden fine-grained shadowed by merged tools · reached via graph/lsp dispatch
FINE
symbol / graph fine-grainedlookup · dependency · entrypoints · impact · implementations · smart_context · organize_imports · fix_diagnostics
workspaceTools.ts:2849–2967graphQuery.ts
LSP + AST
Hidden semantic query tools, reached via lsp_edit dispatch (organize imports, quick fixes), and serving as the AST fallback backend for lsp point queries (symbol lookup, dependency subgraph, entry points, change impact, interface implementations, smart context). The public graph tool itself is also hideFromLlm. All built on ProjectGraph or LSP.
After registration these tools are uniformly hideFromLlm via oldToolNames; the public graph tool is additionally hideFromLlm'd separately at workspaceTools.ts:3793. smart_context = getWorkspaceSmartContext(lookup + entrypoints(5) + dependency).
03

Command & Process Command & Process

exec / shell / proc
Execution surfaceblocking / background / persistent session
EXEC
exec→ workspace_run_command / start_background / start_preview · :2253 / :2403 / :2418
background:true → backgroundpreviewUrl → preview
Plain text
Runs a command, blocking by default. background:true runs in the background and returns a pid; with previewUrl it starts a preview session. timeoutSeconds defaults to 30, max 600.
Dispatch: exec → background? → workspace_start_background_command / workspace_start_preview_session, otherwise workspace_run_command.
SHELL
shell→ shell_* · :2546 / :2557 / :2563 / :2573 / :2601
action: open|send|read|close|list
Plain text
Persistent shell sessions: open starts one, send issues a command, read reads the output tail, close closes it, list lists them all. send takes command+args or input (interactive prompts only).
Dispatch: shellshell_open_session / shell_send_input / shell_read_output / shell_close_session / shell_list_sessions.
PROC
proc→ workspace_*_background_processes · :2441 / :2447 / :2457
action: list|stop|stop_all
Plain text
Background process management (created by exec background). With no action it lists by default; stop stops a given pid; stop_all stops them all.
Dispatch: procworkspace_list_background_processes / workspace_stop_background_process / workspace_stop_all_background_processes.
04

Git Version Space

8 actionsCodePapr isolated version space
Does not touch the user's repoauto backup branch
GIT
git→ workspace_git_* · :3053 / :3057 / :3091 / :3116 / :3141 / :3158 / :3179 / :3222
action: status|diff|log|branch|stage|commit|restore|reset
Plain text
CodePapr's isolated version space (does not touch the user's own Git repo). commit requires message; branch requires branchName; reset requires target and auto-creates a backup branch; restore/reset create a safety snapshot by default beforehand.
Dispatch: gitworkspace_git_status/diff/history/branch_checkout/stage/commit/restore/reset. There is also a hidden workspace_restore_undo (:3255). Parameters include snapshot / includeUntracked / backupBranchPrefix.
05

Web & Browser Web & Browser

web_fetch / web_download / web_search / browser / open
Built-in browserfull support on desktop
WEB
web_fetch / web_download / web_search→ web_fetch_url / web_download_file / web_search · :2375 / :2387 / :2342
web_search natively visiblesearxng
Plain text
web_fetch reads a web page body and converts it to plain text (maxBytes defaults to 20000); web_download downloads a file to .CodePapr/downloads/; web_search is a native fine-grained tool (not via the merge layer), goes through searxng, and can be directly visible to the LLM.
web_fetch/web_download are forwarded via the merge layer; web_search is registered directly (when !disableWebSearchTools), with parameters query/maxResults/searxng*.
BRWS
browser→ browser_*_page · :2611 / :2625 / :2639 / :2647 / :2666 / :2691 / :2708 / :2729
action: open|navigate|reload|close|click|type|read|screenshot|get
Plain text
Built-in browser interaction: open/navigate/reload/close, click an element, type text, read the DOM, screenshot, get state. open/navigate require url; click/type require selector; type requires text. Full support on desktop only.
Dispatch: browser → browserHandler → browser_open_page/navigate_page/reload_page/click/input_text/read_dom/take_screenshot/close_page. There are also preview variants (browser_*_preview) serving exec previewUrl.
OPEN
open→ workspace_open_in_browser · :2305
system default browser
Plain text
Opens a URL or an in-project HTML file in the system default browser.
Dispatch: open → openHandler → workspace_open_in_browser.
06

App & Misc App & Misc

app_render / app_* / skill / question / todo
App modeapp_render is the primary output
APP
app_render / app_list / app_start / app_stop / app_delete· :1977 / :2168 / :2197 / :2227 / :2240
app_render natively visible.CodePapr/apps/<appId>
Plain text
app_render is the primary output tool of App mode: it renders an interactive HTML app into the panel (sandboxed iframe + Papr SDK). app_list/start/stop/delete manage the backend lifecycle of registered .papr apps. app_render is always excluded from subagents (to prevent nesting).
app_render parameters: appId(kebab-case) / title / html / permissions / agents / level / command+args+port. app_list and the other 3 are visible to the LLM via the merge layer.
AUX
skill / question / todo / local_time_now→ skill_load · :2321 · question handler :3494
skill via merge layerquestion Plan mode only
Plain text
skill loads instruction files from .CodePapr/skills/; question asks the user a question (Plan mode, returns a __question structure); todo is a live task list; local_time_now is local time (fine-grained, within the mode whitelist).
skill forwards to skill_load via the merge layer; question returns structured markers via questionHandler; see agentRuntime.worker.ts:76-78 for the mode tool whitelist.

Five facts about the current state

Why "tools are bloated and LSP/AST aren't wired well" — the starting point for refactoring.
F·01
degradation chain wired into lsp point queries (refactored)

The lsp→ast→regex degradation in UnifiedSymbolDispatcher (with Rust symbol_provider.rs as the engine) originally only served project-map symbol extraction. Now extended: the 9 navigation actions of lsp degrade to the AST project graph via astFallback (workspaceTools.ts:2930) when LSP is unavailable/returns nothing, tagged with source/confidence. read/write/edit/patch are still not wired to language intelligence.

F·02
read is dumb

workspace_read_file directly invoke('read_text_file') returns plain text (workspaceTools.ts:1913). It doesn't distinguish file types, gives no symbol outline, and doesn't tell the LLM where this file sits in the dependency graph.

F·03
no feedback loop after a change

write/edit/patch end once they hit disk. diagnostics is a standalone tool; the LLM must remember to call it itself. If the agent breaks type checking, it has no idea until the next call—this is the biggest gap in a good harness.

F·04
graph does a full rebuild every time

Every graph action re-lists the whole workspace + reads each file from disk + queries LSP + builds the graph + enriches it (buildIntelligenceProjectGraph:1785). Zero caching. A lookup→dependency→impact triple is three full rebuilds.

F·05
edit is pure literal matching

applySearchReplacePatch uses String.indexOf for exact matching (searchReplaceDiff.ts:51-78). When the same text appears in multiple functions, you can only guess via expectedOccurrences or by lengthening search—no symbol anchor available.

F·06
overlapping mental models (consolidated)

The former read / graph(overview) / list all returned structure, graph(lookup) and lsp(definition) were both "finding symbols", and graph(impact)=dependency(incoming) had overlapping responsibilities—now consolidated: graph is hidden from the LLM, project structure goes to list(action: overview), and point queries (definition/references/implementation/call hierarchy) are unified into lsp, which degrades to AST internally as needed. The LLM faces a single lsp tool, with no need to arbitrate between overlapping tools.

The full chain of a single tool call

Using edit as an example — from LLM invocation to Rust persisting to disk.
L0LLM calls edit
L1Merged tool definitionmergeToolDefs
L2Dispatcher mappingedit→apply_patch
L3Fine-grained handlerre-read source 20MB
L4Literal SEARCH/REPLACEindexOf exact match
L5invoke write_text_fileTauri → Rust
L6Re-read verify + editHistorynotifyMutation