Project Files
README.md
An LM Studio plugin that gives local LLMs eight read-oriented git tools built on @lmstudio/sdk and simple-git. The plugin lets a model inspect any git repository under the chat's working directory — staged/unstaged status, diffs, commit history, branches, file content at any ref, tracked-file listings, and content search — and clone new repositories into that directory for further inspection. All tools shell out through simple-git's discrete-argument process spawning (never a shell), every path is validated to stay inside the working directory, and git_clone is the only tool that writes to the filesystem.
Every tool takes a repoName parameter — the directory name of a repository inside the chat's working directory. Paths that resolve outside the working directory are rejected before any git command runs.
Returns the current state of the working tree as JSON: staged, unstaged, untracked, conflicted, and renamed entries plus the current branch and tracking info.
| Parameter | Type | Notes |
|---|---|---|
repoName | string | Required. Directory name of the cloned repository. |
Returns the unified diff of staged or unstaged changes, optionally scoped to a single file. Returns (no changes) when the diff is empty.
| Parameter | Type | Notes |
|---|---|---|
repoName | string | Required. |
staged | boolean | Optional, defaults to false. When true shows the staged diff (--cached); otherwise shows the working-tree diff. |
file | string | Optional. Restricts the diff to a single file path within the repo. |
Returns recent commits as JSON, in simple-git's log.all shape (hash, date, message, author, refs).
| Parameter | Type | Notes |
|---|---|---|
repoName | string | Required. |
count | int 1–100 | Optional, defaults to 10. |
branch | string | Optional branch name. Defaults to the current branch. |
Returns local or remote branch info plus the repository root path.
| Parameter | Type | Notes |
|---|---|---|
repoName | string | Required. |
remote | boolean | Optional, defaults to false. When true lists remote branches (--remotes) instead of local. |
Returns { current, branches, repoRoot } as JSON.
Returns the contents of a commit or a file at a specific ref, with line-based pagination. When a file is supplied, the tool first checks blob size with git cat-file -s and refuses to load anything larger than 10 MB. Post-load output is also capped at 10 MB.
| Parameter | Type | Notes |
|---|---|---|
repoName | string | Required. |
ref | string | Optional, defaults to HEAD. Commit hash, tag, or ref. Whitespace is rejected. |
file | string | Optional file path within the commit. Omit to show the commit itself. |
offset | int 0–10 000 000 | Optional. 0-based line number to start reading from. |
limit | int 1–10 000 | Optional. Maximum number of lines to return. Omit for all available lines. |
Returns { content, total_lines, from_line, to_line } as JSON.
Lists tracked files as a recursive flat array, optionally narrowed by a git pathspec, with offset/limit pagination. Output capped at 10 MB; narrow with a pathspec when listing very large repos.
| Parameter | Type | Notes |
|---|---|---|
repoName | string | Required. |
pathspec | string | Optional git pathspec — exact filename, directory path, or wildcard (e.g. src/, **/*.ts). Omit to list every tracked file. |
offset | int 0–10 000 000 | Optional. 0-based starting index. |
limit | int 1–10 000 | Optional. Maximum files to return. |
Returns { files, total_count, from, to } as JSON.
Runs git grep over tracked files and returns matches as JSON, with offset/limit pagination. Raw output is capped at 10 MB; narrow with a pathspec or a more specific pattern when searching very large repos.
| Parameter | Type | Notes |
|---|---|---|
repoName | string | Required. |
pattern | string | Required. Basic regular expression by default; literal when fixedStrings is true. |
pathspec | string | Optional git pathspec to narrow the search. |
caseInsensitive | boolean | Optional, defaults to false. Adds -i. |
fixedStrings | boolean | Optional, defaults to false. Adds -F (literal-string match). |
wordRegexp | boolean | Optional, defaults to false. Adds -w (whole-word match). |
offset | int 0–10 000 000 | Optional. 0-based starting match index. |
limit | int 1–10 000 | Optional. Maximum matches to return. |
Returns { matches, total_count, from, to } as JSON. Each match carries path, line, and text parsed from git grep --no-color -n -z -I --full-name.
Clones a remote repository into the chat's working directory. The destination directory name defaults to the URL's basename (with .git stripped) and is validated to stay inside the working directory before the clone runs. This is the only tool that writes to the filesystem.
| Parameter | Type | Notes |
|---|---|---|
repoUrl | string | Required. The git URL to clone. |
repoName | string | Optional destination directory name. Defaults to the repository name inferred from repoUrl. |
branch | string | Optional branch (--branch). Defaults to the repository's default branch. |
depth | int ≥ 1 | Optional commit depth (--depth). Use 1 for a shallow clone. |
Returns a confirmation string of the form Cloned "<repoUrl>" to "<repoName>".
Install the plugin through LM Studio's plugin browser. Once enabled, the eight tools become available to any model that supports tool calls.
Requires Node.js ≥ 22.
npm run push publishes the plugin to the LM Studio Hub (lms push).
The plugin is intentionally narrow. Read-only by default, single write tool, no shell:
The plugin has no user-facing settings — every constraint (size caps, pagination ceilings, max ref/path lengths) is fixed in source. Repository inspection happens entirely against repos under the chat's working directory.
With the plugin enabled you can ask the assistant to inspect any repository inside the chat's working directory ("what changed since last commit?", "show me the README at v1.2.0", "find every TODO in this repo"), or ask it to clone something new for inspection ("clone https://github.com/foo/bar so I can ask questions about it"). The assistant will pick the appropriate tool — typically git_clone first if the repo isn't present, then git_ls_files/git_grep to locate things and git_show/git_log/git_diff to read them.
No test suite is configured.
MIT — see LICENSE.
repoName (and the git_clone destination) is resolved through resolveAndValidateRepoPath and rejected if it escapes controller.getWorkingDirectory(). This is the only error that throws rather than being returned as a string — the harness surfaces it to the user.git_status, git_diff, git_log, git_branch, git_show, git_ls_files, and git_grep invoke only read subcommands. No commit, push, branch-creation, merge, checkout, or reset operations are exposed.git_clone is the only tool that touches the filesystem; its destination is path-validated.simple-git, which spawns processes with discrete argument arrays. There is no shell-interpreted string anywhere in the plugin.git_show, git_ls_files, and git_grep route their string parameters through the shared gitSafeString zod schema, which rejects values starting with - so they cannot be reinterpreted as git flags.git_show checks cat-file -s before loading file blobs and caps post-load output at 10 MB. git_ls_files and git_grep cap raw output at 10 MB and ask the model to narrow with a pathspec when the cap is hit.simple-git calls in try/catch and routes caught errors through formatGitError, per the SDK guidance to return recoverable errors as strings.npm run build — compile TypeScript (src/ → dist/).npm run dev — run the plugin in LM Studio dev mode (lms dev).npm run push — publish to the LM Studio Hub (lms push).npm run lint / npm run lint:fix — ESLint on src/**/*.ts.npm run format / npm run format:check — Prettier.npm run knip — dead-code / unused-export check.git clone https://github.com/packern/git-tools.git
cd git-tools
npm install
npm run dev # runs `lms dev`