Purpose of this document: illustrate the user and developer value of the
/gitcommand in an application based on Pythia-webview2.
This document presents the Git plugin as a second plugin example after/snippet: where/snippetdemonstrates local prompt reuse,/gitdemonstrates external context collection from a developer tool.
This document does not cover full plugin installation or project creation in the host application.
Important
The /git command is available only when the corresponding plugin is installed and loaded by the host application.
It also requires a configured Git working directory and a git executable available from the process PATH.
Without this plugin, the command is not interpreted by Pythia-webview2 and should be considered unavailable in the runtime environment.
- 1. Why a
/gitcommand? - 2. Position in the plugin examples
- 3. What this command demonstrates
- 4. Command surface
- 5. Central workflow: collect, edit, send
- 6. Command behavior by category
- 7. Formatting of injected context
- 8. Preparing a small demo repository
- 9. Progressive discovery
- 10. Suggested walkthrough
- 11. Safety model
- 12. External process execution
- 13. Encoding and Git configuration
- 14. Output size and truncation
- 15. Empty output
- 16. Error handling
- 17. Command registry validation
- 18. Degraded scenarios
- 19. Host wiring note
- 20. Code organization
- 21. What the developer should observe
- 22. What the user should observe
- 23. Limits and possible extensions
- 24. Summary
An application that integrates an LLM becomes much more useful when it can receive real project context:
- the current branch;
- the working tree status;
- the unstaged diff;
- the staged diff;
- recent commits;
- a specific commit or object;
- blame information for a file or a line range.
Without a command plugin, a developer usually has to leave the LLM interface:
terminal → git diff → copy → return to LLM UI → paste → format → ask a question
The /git command turns that workflow into a controlled context-collection step that happens directly from the prompt input field.
For example:
/git diff
fills the prompt input field with the collected diff. The user can then add a question such as:
Could you review this diff and identify likely edge cases, regressions, or memory issues?
The command does not submit anything automatically. It only prepares the context. The user stays in control: they can edit, extend, or send the final prompt manually.
/git is the second plugin example.
The first example, /snippet, demonstrates a local prompt library: it stores user-defined prompt fragments, persists them locally, and writes selected snippets into the prompt input field.
/git demonstrates a different kind of extension: it collects context from an external developer tool, formats it, and injects it into the prompt input field.
| Plugin | Demonstrates | Context source | Main value |
|---|---|---|---|
/snippet |
local prompt reuse and persistence | user-authored prompt fragments | avoid retyping stable instructions |
/git |
external process-based context collection | Git repository state | bring live development context into the LLM workflow |
This progression matters: the goal is not to show two isolated commands, but to show that a Pythia-webview2 application can be extended with focused business plugins without modifying the core UI component.
/git is intentionally limited from the user's point of view, but it is more advanced than a simple convenience command from an integration point of view.
It demonstrates:
- a Pythia command with multiple Git-oriented actions;
- controlled execution of an external tool;
- concurrent capture of
stdoutandstderr; - timeout handling for external processes;
- injection of generated context into the prompt input field;
- clear user feedback for Git errors and environment errors;
- fixed action mapping instead of arbitrary shell execution;
- argument validation before reaching Git;
- truncation of large outputs;
- Markdown fenced formatting for LLM-readable context;
- a reusable process-runner abstraction for future plugins;
- separation between the command adapter, business service, and process execution layer.
This is therefore not only a Git sample. It is a compact example of how a developer can add a business-specific context collector to a Pythia-webview2 application.
/git branch
/git status
/git diff [ref]
/git staged
/git log [n]
/git show <ref>
/git blame <file> [range]
| Command | Purpose |
|---|---|
/git branch |
Injects the current branch name. |
/git status |
Injects git status --short. |
/git diff |
Injects the unstaged diff. |
/git diff ref |
Injects a diff against a specific reference or range. |
/git staged |
Injects the staged diff, equivalent to git diff --cached. |
/git log |
Injects recent commits using the default count. |
/git log n |
Injects the last n commits. |
/git show ref |
Injects the output of git show <ref>. |
/git blame file |
Injects blame information for a file. |
/git blame file range |
Injects blame information for a line range. |
The command surface is deliberately read-only. The plugin collects repository context; it does not modify the repository.
The central workflow is:
/git diff
Expected effect: the prompt input field is pre-filled with a fenced block containing the Git diff.
The user can then add the actual question:
Could you review this diff and identify likely edge cases, regressions, or memory issues?
The final prompt sent to the LLM contains both:
- the collected repository context;
- the user's explicit request.
This is an important product decision.
/git diff does not ask the LLM anything by itself. It does not auto-submit. It does not hide the collected context. It simply prepares the prompt input field and lets the user decide what to do next.
/git branch
/git status
These commands help the user expose the current repository state to the LLM.
Typical use cases:
- confirm the active branch;
- show whether the working tree is clean;
- provide a compact overview before asking a review or debugging question.
/git diff
/git staged
These are the most important commands for code-review workflows.
Typical use cases:
- ask for a review of unstaged changes;
- ask whether staged changes are coherent before committing;
- compare what is already staged with what remains in the working tree.
Example:
/git staged
Then add:
Is this staged change coherent as a commit? Please identify missing tests or risky assumptions.
/git log
/git log 5
/git show HEAD
/git show HEAD~1
These commands help the user provide historical context to the LLM.
Typical use cases:
- summarize recent commits;
- explain a particular commit;
- review the latest commit;
- compare a change with nearby history.
/git blame a.txt
/git blame a.txt 1,1
These commands help the user investigate where a line came from.
Typical use cases:
- understand the origin of a line;
- ask the LLM to explain a local change in historical context;
- narrow the context to a specific range instead of pasting an entire file.
The plugin injects output into the prompt input field as fenced Markdown.
Example shape:
````diff
diff --git a/a.txt b/a.txt
...
````The sample uses a four-backtick fence.
This matters because Git diffs may contain source files, Markdown content, or examples that already contain three-backtick blocks. A four-backtick fence reduces the risk that the injected context accidentally breaks the prompt structure.
The info string depends on the command:
| Output kind | Info string |
|---|---|
| diff-like output | diff |
| plain textual output | text |
The goal is to keep the context readable both by the user and by the LLM.
The /git sample is easier to test with a small repository whose state is known in advance.
Open a Windows cmd.exe prompt and run:
cd C:\tmp
mkdir demo-git && cd demo-git
git init
git config user.email "test@example.com"
git config user.name "Demo"
echo "# Demo" > README.md
git add README.md
git commit -m "initial"
echo "Hello" > a.txt
git add a.txt
git commit -m "add a.txt"
echo "World" >> a.txt
git add a.txt
git commit -m "extend a.txt"
echo "Unstaged change" >> a.txt
echo "Staged change" > b.txt
git add b.txtThen configure the host application with this repository root as the Git working directory:
FGitService := TGitService.Create(FRunner, 'C:\tmp\demo-git');At this point, the repository contains:
| Item | State |
|---|---|
README.md |
committed in the initial commit |
a.txt |
committed, then modified again but not staged |
b.txt |
newly created and staged |
| history | three commits |
| branch | main or master, depending on the local Git configuration |
This gives predictable results for the walkthrough:
| Command | Expected result |
|---|---|
/git branch |
current branch, usually main or master |
/git status |
M a.txt and A b.txt |
/git diff |
unstaged diff for a.txt |
/git staged |
staged diff for b.txt |
/git log 3 |
the three commits |
/git show HEAD |
the extend a.txt commit |
/git blame a.txt |
blame output for the committed lines |
/git branch
Expected result: the current branch is injected into the prompt input field.
Example:
main
or:
master
This confirms that:
- the plugin is active;
gitis available;- the configured working directory is a Git repository.
/git status
Expected result with the demo repository:
M a.txt
A b.txt
The exact spacing is Git's own --short format.
/git diff
Expected result: a fenced diff block containing the unstaged modification of a.txt.
The user can then add:
Please review this change and identify possible edge cases.
/git staged
Expected result: a fenced diff block containing the staged creation of b.txt.
This command exists instead of exposing /git diff --cached. The plugin keeps command actions explicit and avoids passing arbitrary Git options from the prompt input field.
/git log 3
Expected result: three one-line commits.
Example shape:
<hash> extend a.txt
<hash> add a.txt
<hash> initial
/git show HEAD
Expected result: the latest commit, including its message and diff.
Another useful example:
/git show HEAD~2
Expected result: the initial commit.
/git blame a.txt
Expected result: blame information for committed lines in a.txt.
To restrict blame to one line:
/git blame a.txt 1,1
Expected result: blame information for line 1 only.
This scenario is enough to show the command's value in a few minutes.
- create the small demo repository from section 8;
- configure the host with
C:\tmp\demo-gitas the Git working directory; - run the application in debug mode;
- keep a terminal open on the repository if you want to compare with raw Git output.
| # | Command | Expected result |
|---|---|---|
| 1 | /git branch |
current branch, usually main or master |
| 2 | /git status |
short status with a.txt modified and b.txt staged |
| 3 | /git diff |
unstaged diff for a.txt |
| 4 | add a review question manually | the final prompt contains diff + user question |
| 5 | /git staged |
staged diff for b.txt |
| 6 | /git log 3 |
three commits |
| 7 | /git show HEAD |
latest commit with diff |
| 8 | /git blame a.txt 1,1 |
blame for one line |
Run:
/git diff
Then add:
Could you review this diff and identify likely edge cases, regressions, or memory issues?
Expected result: the LLM receives a single prompt containing both the collected diff and the user's review request.
This is the main user-facing value of the plugin.
The /git plugin is designed as a context collector, not as a general-purpose Git shell.
There is no command like:
/git raw ...
Each exposed action maps to a fixed Git subcommand.
This keeps the plugin predictable, testable, and easier to explain.
Examples:
| Plugin action | Git command shape |
|---|---|
/git status |
git status --short |
/git diff |
git diff |
/git staged |
git diff --cached |
/git log n |
git log --oneline -n n |
/git branch |
git branch --show-current |
/git show ref |
git show ref |
/git blame file range |
git blame -L range file |
The user can provide refs, file paths, and ranges only in the positions that the service accepts.
User-provided refs, file paths, and ranges are rejected when they start with -.
Rejected examples:
/git diff --upload-pack=evil
/git show --version
/git show -h
/git blame --output=evil.txt
/git blame a.txt -L 10
This policy is intentionally restrictive. A rare file name such as -foo is rejected. For this sample, that trade-off is acceptable because the plugin is meant to demonstrate a bounded and safe context-collection pattern.
The exposed actions are read-only. They inspect repository state and history, but they do not commit, reset, checkout, merge, rebase, or write files.
This keeps the demo focused on LLM context collection rather than Git automation.
The plugin uses a generic shell runner abstraction instead of putting process-management code directly into the Git service.
IShellRunner is a reusable primitive for command plugins that need to run an external process and capture its output.
It is not Git-specific. Future plugins can reuse the same idea for commands such as:
/npm
/docker logs
/curl
/pytest
/maven
The Windows runner captures stdout and stderr using two reader threads.
This avoids a common deadlock pattern:
- the child process writes a lot to
stdout; - the
stdoutpipe buffer fills; - the child blocks while writing;
- the parent waits for the process to exit;
- the process cannot exit because the parent is not draining the pipe.
Reading both streams concurrently makes the runner robust enough for tools that produce large outputs or error messages.
The runner applies a hard timeout.
If the process takes too long, it is terminated and the partial output already captured from stdout and stderr can still be surfaced.
In the sample Git service, the default timeout is short enough for a demo-oriented interaction and can be adjusted by the host when constructing the service.
Every Git invocation prepends configuration arguments that make output more predictable:
-c core.quotepath=false
-c i18n.logoutputencoding=utf-8
The goal is to:
- keep file names readable;
- force log output to UTF-8;
- reduce dependence on the user's global Git configuration;
- improve the quality of the text injected into the prompt input field.
The runner decodes captured output as UTF-8 using a lossy strategy so that unexpected non-UTF-8 bytes in diffs do not crash the whole command.
Git output can be very large, especially for diffs and history.
The sample applies a maximum injected output size:
200000 characters
When the output exceeds that limit, it is truncated and a footer is appended:
[output truncated to 200000 characters]
This protects the prompt input field and keeps the demo usable on larger repositories.
An empty Git output is often meaningful.
Examples:
| Command | Possible meaning of empty output |
|---|---|
/git status |
clean working tree |
/git diff |
no unstaged diff |
/git staged |
nothing staged |
/git branch |
detached HEAD |
The sample should surface this case explicitly instead of injecting an invisible empty block.
Depending on host policy, this can be displayed as a warning or as command feedback such as:
git status --short: empty output
For a product-oriented demo, a friendlier message may be preferable:
Working tree clean
or:
No staged diff
The important point is to document the behavior: empty output is not the same thing as a process failure.
If git is not available from the process PATH, process creation fails and the system error is surfaced.
Possible messages:
The system cannot find the file specified
or on a French Windows:
Le fichier spécifié est introuvable
No separate where git probe is required. The actual process-launch error is already meaningful.
If the host configures a non-existing working directory:
TGitService.Create(FRunner, 'C:\does\not\exist')Expected result:
Git working directory does not exist: C:\does\not\exist
If the working directory exists but is not a Git repository, Git itself reports the problem.
Example configuration:
TGitService.Create(FRunner, 'C:\Windows')Command:
/git status
Expected result shape:
fatal: not a git repository (or any of the parent directories): .git
Some values are syntactically allowed by the plugin but invalid for the current repository.
Examples:
/git show no_such_ref_xyz
/git diff no_such_ref
/git blame no_such_file.txt
The plugin lets Git decide and surfaces the resulting stderr message.
Some errors are not handled by the Git service itself, but by command validation in the command registry.
| Command | Expected status |
|---|---|
/git status extra |
csWrongArgCount: one argument received, zero expected |
/git diff a b |
csWrongArgCount: two arguments received, zero or one expected |
/git show |
csWrongArgCount: zero arguments received, one expected |
/git blame |
csWrongArgCount: zero arguments received, one or two expected |
/git bogus |
csUnknownAction |
This separation matters to the developer:
- the registry validates action existence and arity;
- the plugin parses only command-level values such as
/git log n; - the service validates refs, file paths, ranges, working directory, process results, and Git errors.
| Command | Expected result |
|---|---|
/git log abc |
error: argument must be a positive integer |
/git log 0 |
error: argument must be a positive integer |
/git log -5 |
error: argument must be a positive integer |
/git log 2.5 |
error: argument must be a positive integer |
/git log 1 |
OK, one commit |
| Command | Expected result |
|---|---|
/git diff --upload-pack=evil |
invalid Git reference because it starts with - |
/git show --version |
invalid Git reference because it starts with - |
/git show -h |
invalid Git reference because it starts with - |
/git blame --output=evil.txt |
invalid file path because it starts with - |
/git blame a.txt -L 10 |
invalid range because it starts with - or contains spaces |
| Command | Expected result |
|---|---|
/git status extra |
wrong argument count |
/git diff a b |
wrong argument count |
/git show |
wrong argument count |
/git blame |
wrong argument count |
/git bogus |
unknown action |
A large repository can be used to test truncation.
Example:
cd C:\tmp
git clone --depth 5000 https://github.com/torvalds/linux.gitThen configure the working directory to that clone and run:
/git log 100000
Expected result: the output is injected up to the limit and ends with:
[output truncated to 200000 characters]
For testing only, construct the service with a very small timeout:
FGitService := TGitService.Create(FRunner, 'C:\tmp\demo-git', 1);Then run:
/git log
Expected result shape:
Process timed out after 1 ms
After the test, restore a normal timeout value.
The host application creates the service and registers the plugin.
Example shape:
Pythia.OnRegisterCommandPlugins :=
procedure
begin
FRunner := TShellRunner.Create;
FGitService := TGitService.Create(FRunner, 'C:\tmp\demo-git');
FGitService.Browser := Pythia;
Pythia.CommandLine.RegisterPlugin(TGitPlugin.Create(FGitService));
end;The important design point is that the host owns the working-directory choice.
There is no implicit fallback to:
GetCurrentDir
ExtractFilePath(ParamStr(0))
The repository root is explicit. That keeps the plugin predictable and makes the demo easier to reason about.
The sample is split into four units.
| Unit | Role |
|---|---|
Demo.Shell.Runner.pas |
generic process runner with stdout/stderr capture and timeout |
Demo.Git.Plugin.Intf.pas |
Git service interface and operation result type |
Demo.Git.Plugin.Service.pas |
Git validation, execution, formatting, truncation, and injection |
Demo.Git.Plugin.pas |
command adapter between Pythia command-line actions and IGitService |
This unit provides the reusable process execution primitive.
It is responsible for:
CreateProcess-based execution;- command-line construction;
- working-directory propagation;
- stdout capture;
- stderr capture;
- concurrent pipe draining;
- timeout enforcement;
- UTF-8 decoding;
- returning a structured
TShellRunResult.
This unit is intentionally independent from Git.
This unit defines the business contract.
It contains:
TGitOperationResult;IGitService.
The interface makes the command adapter independent from the concrete Git implementation. A future implementation could use another backend, such as a library-based Git implementation or a sandboxed runner.
This unit contains the Git-specific business logic.
It is responsible for:
- validating the working directory;
- validating refs, file paths, and ranges;
- building fixed Git command shapes;
- executing Git through
IShellRunner; - handling process failures and Git exit codes;
- truncating large outputs;
- formatting fenced Markdown;
- deferring prompt input injection so it lands after the runtime input reset.
This unit is the command adapter.
It is responsible for:
- declaring the
/gitactions; - validating action arity through
AddAction; - parsing
/git log n; - delegating execution to
IGitService; - translating
TGitOperationResultinto the command framework result.
It deliberately does not contain Git process code.
The plugin developer does not need to write:
- a prompt textarea;
- button handling;
- chat rendering;
- vendor-specific LLM code;
- prompt submission logic;
- error rendering UI;
- browser message plumbing.
The developer writes a focused extension:
command → validation → external context collection → formatting → prompt input injection
That is the main technical value of the plugin model.
The core component does not become a Git client.
The Git-specific behavior lives in the plugin and service. The host loads that plugin when it wants Git context collection.
This keeps the main component generic while still allowing business-oriented extensions.
The Git sample introduces a reusable external-process primitive.
The same pattern can support other plugins later:
/npm test
/docker logs
/curl
/pytest
/maven
/custom-tool
The Git plugin is therefore also an example of a reusable infrastructure piece for future command plugins.
The design can be tested at several levels.
IShellRunner can be tested with a real Windows command:
cmd /c echo helloTGitService can be tested with a mock IShellRunner returning prebuilt TShellRunResult values.
TGitPlugin can be tested with a mock IGitService to verify:
- action mapping;
/git log nparsing;- wrong-arity behavior;
- unknown-action behavior.
This sample does not pretend to be a full Git client.
It documents its limits:
- no arbitrary Git command;
- no shell access;
- no repository modification;
- Git must be available from
PATH; - the working directory is provided by the host;
- some rare argument forms are rejected for safety;
- large output is truncated;
- empty output is surfaced explicitly.
Explicit limits are useful for an integration sample because they make the intended scope clear.
The user does not need to leave the LLM interface to collect common Git context.
Before:
terminal → git command → copy → prompt field → paste → question
After:
/git diff → question
The injected context is:
- collected from the actual repository;
- formatted as a fenced block;
- clearly separated from the user question;
- easier for the LLM to interpret.
The plugin does not auto-submit.
This matters because the user may want to:
- shorten the context;
- add extra instructions;
- ask a specific review question;
- remove sensitive parts;
- cancel the request.
The command prepares the prompt; it does not replace the user's judgment.
The command names map to familiar Git concepts:
branch
status
diff
staged
log
show
blame
The user does not need to learn a new abstract model. The command simply brings Git context into the LLM workflow.
The sample should remain read-only, but several extensions are possible.
Possible examples:
/git grep <pattern>
/git file <path>
/git changed
/git recent
/git conflicts
/git patch <ref>
Each new action should remain explicit and bounded.
The current model injects one collected block into the prompt input field.
A future command could append context instead of replacing the current input, but that requires a reliable primitive to read or extend the current input field content.
Possible shape:
/git append diff
or:
/git diff --append
The second form would require revisiting the safety model because it introduces option-like syntax.
The sample can improve user experience by translating empty Git outputs into domain-specific messages:
| Command | Friendlier message |
|---|---|
/git status |
Working tree clean |
/git diff |
No unstaged diff |
/git staged |
No staged diff |
/git branch |
Detached HEAD or no current branch |
The host currently provides the working directory explicitly.
A real application could provide:
- a project picker;
- a recent repositories list;
- per-conversation repository binding;
- workspace-aware configuration.
This should remain host-owned rather than hidden inside the plugin.
/git is a context-collection command for Pythia-webview2.
It is the second plugin example after /snippet:
/snippetdemonstrates local prompt reuse and persistent user-defined content;/gitdemonstrates external context collection from a developer tool.
The command does not turn Pythia-webview2 into a Git client. It shows how a plugin can collect useful business context, format it safely, and inject it into the prompt input field while leaving the final request under user control.
For users, this reduces friction when asking an LLM to review, explain, or summarize repository state.
For developers, it demonstrates how to extend the LLM interface with a focused, testable, business-oriented plugin without modifying the core component.
The important architectural point is simple:
Pythia-webview2 provides the interface.
The plugin provides the business context.
The user remains in control of the final prompt.