Open WebUI Tools that give a meta model (an LLM configured in Open WebUI) read-only access to source code (Open WebUI's own and community tool repositories) for understanding, inspecting, and comparing it.
Four self-contained scripts (one per Open WebUI Tool), generated from
templates/*.py.tpl + common.py:
| Script | Tools |
|---|---|
dist/repos.py |
cexp_clone_repo, cexp_fetch_repo, cexp_pull_repo, cexp_list_repos, cexp_remove_repo |
dist/files_search.py |
cexp_list_files, cexp_read_file, cexp_search_text, cexp_search_symbol |
dist/commits.py |
cexp_list_branches, cexp_list_tags, cexp_list_commits, cexp_search_history, cexp_show_commit, cexp_compare_commits |
dist/code_explorer.py |
all 15 tools in one script |
cexp_read_file/cexp_list_filestake aref(branch, tag, or commit): read a file, or list the files, as they exist at that version (from the local clone, no network, no working-tree changes).cexp_list_filesis non-recursive by default: it lists the direct entries underpath; passrecursive=Trueto descend (optionally bounded bymax_depth, which requiresrecursive=True).cexp_compare_commitstakescontext(unified-context lines) andpath: narrow a large diff to a single file.cexp_show_committakesstat=Truefor a metadata + changed-file summary (no diff body);cexp_list_commitstakesfirst_parent=Trueto trace the merge narrative, and its items carryauthoranddate.cexp_search_texttakesfiles_only/count_onlyfor per-file aggregate results (no line matches).cexp_search_text/cexp_search_symboltake aref: search the files as they exist at a branch/tag/commit (from the local clone, no network, no working-tree changes) — grep a released tag's content instead of only the working tree.cexp_search_history(query, ...)answers "when was this string introduced or removed?" (git pickaxe).cexp_list_branchestakesmerged=True/Falseto filter by merge state.cexp_remove_repo(repo, dry_run=True)previews a deletion (path + size); without dry_run it deletes the clone.cexp_list_reposreports each clone'soriginand on-disksize.- Truncated results carry a
hint(intruncatedfor JSON tools, ahint:line for raw-text tools) telling the agent how to narrow; "repo not found" errors list the existing clones.
Use the three per-group scripts for per-group tool access (e.g. attach only
read/search tools to a model). dist/code_explorer.py is a single-paste
alternative that exposes everything at once.
common.py (the security-critical logic) is inlined into each script at build
time; the scripts are self-contained (no import common).
META_MODEL_PROMPT.md is the recommended system prompt for the meta model.
- Python 3.9+ (build + tests).
git>= 2.39 onPATH.fd/rgare NOT required: listing, reading, and searching are pure Python (pathspec, regex; stdlib fallbacks).
python build.py # inline common.py into templates/ -> dist/
python -m pytest # test suitedist/ is committed so the scripts can be pasted into Open WebUI without
building.
python build.py(or use the committeddist/).- Admin → Tools → +: paste
dist/repos.py,dist/files_search.py,dist/commits.py(one per script), or justdist/code_explorer.py. - Valves:
repos_pathempty unless you're not usingOWUI_REPOS_PATH;max_results50,max_lines200,max_bytes20480. - Admin → Models → → Tools: attach the script(s).
- Test against a small public repo first.
Storage location resolution: Valve repos_path → env OWUI_REPOS_PATH →
/usr/local/src.
Mount a volume at /usr/local/src and set once at the container level:
OWUI_REPOS_PATH=/usr/local/srcA volume is required so clones survive container recreation; the process needs read/write permission on it. The Valve is a logical override; actual write permission comes from the mounted volume.
- Subprocesses:
gitonly, argument arrays, headless env (no prompts, no pager, no user/global config; hostileGIT_*vars likeGIT_DIR/GIT_SSHare purged, andfetch/pullre-validate the remote origin through the protocol allow-list before running). - Read-only for code: only
cexp_clone_repo/cexp_fetch_repo/cexp_pull_repowrite, only inside<repos_path>, only viagit;cexp_remove_repodeletes a clone but only strictly inside<repos_path>(symlinked roots refused;dry_runpreviews). - Path sanitization:
repois<owner>/<name>(components^[A-Za-z0-9_][A-Za-z0-9_.-]*$); file paths checked for absolute/../symlink escapes. - Ref sanitization: refs validated before reaching git (no option injection,
no
..ranges, no revision expressions). - Clone-URL protocol allow-list: only
https,http,git,ssh; scp-likegit@host:pathis accepted (normalized tossh://);file://(local exfiltration) andext::/sh::(git's command-execution URL form) are blocked, as are credentials in URLs (they would be persisted in<repo>/.git/config). SSH clones work only with preconfigured credentials (BatchMode=yesfails cleanly otherwise). Optionalallowed_hostsValve on the Repos script restricts which hosts may be cloned (exact or subdomain on a dot boundary; empty = unrestricted). - One clone per
<owner>/<name>: cloning an existing repo returns anError:naming the existing origin —cexp_fetch_repo/cexp_pull_repowhen it is the same logical repo,cexp_list_reposotherwise (a different host is a namespace collision; a different transport of the same host is the same repo). Never overwrites. - Bounded output: every result capped by the
max_results/max_lines/max_bytesValves, with explicit truncation markers. - No shell, no code execution, no network from the model.
cexp_list_reposreports each clone'srepo, currentbranch, andorigin(the clone URL, showing provider + protocol).cexp_fetch_reporeportsrelease: the most recent release tag, same resolution ascexp_clone_repo(ref="release").- Structured results are JSON (indented, UTF-8, always valid): the
clone/fetch/pull/list/search/commit-enumeration tools, with a structured
truncatedfield when capped.cexp_read_fileand the diff tools return raw text: JSON-escaping code or diffs would obscure them. - Errors are strings, never raised:
Error: <summary>+ optionalcause:;Not found:for missing repos/files;Timed out:for timeouts. - Timeouts: clone 600 s, fetch/pull 120 s, misc 30 s.
cexp_clone_repo(ref="release")checks out the most recent release tag (highestv?X.Y.Zsemver; fallback: newest tag by commit date).cexp_fetch_reporeports that same tag in itsreleasefield after fetching.cexp_pull_repois fast-forward only (git pull --ff-only): no merge commits; fails cleanly on a detached HEAD (usecexp_fetch_repo).