4.4 KiB
Workspace Git controls
Workspace Git controls let the browser inspect Git state for the active session workspace. By default,
WebUI can read status, list branches, show diffs, fetch remote refs, and generate commit-message
suggestions. Actions that modify the repository, index, or worktree are disabled unless the WebUI
process is started with HERMES_WEBUI_WORKSPACE_GIT_DESTRUCTIVE=1.
Trust model - read this first. Once mutating Git actions are enabled, a browser action can run Git commands inside a mounted workspace. Some Git commands can also run repository hook code from
.git/hooks/or a configuredcore.hooksPath. That hook code runs as the WebUI process user, with the WebUI process permissions and environment. Treat hooks that download or execute code as code execution by the WebUI process user.
What works by default
Without HERMES_WEBUI_WORKSPACE_GIT_DESTRUCTIVE=1, WebUI can:
- show repository status
- list branches
- show file diffs
- fetch from the configured remote
- generate commit-message suggestions
Fetch may update remote-tracking refs, but it does not change the worktree, merge branches, create commits, or push changes.
Commit-message generation may send staged or selected diff context to the configured model provider. The UI labels this before generation.
Diffs for untracked files are size checked before WebUI reads file contents. Large or binary files return metadata instead of inline diff text.
What requires explicit enablement
These actions are blocked unless HERMES_WEBUI_WORKSPACE_GIT_DESTRUCTIVE=1 is set:
- stage and unstage
- discard changes
- commit and selected-file commit
- pull and push
- checkout
- branch switching that parks and restores local changes
Leave the flag unset for deployments where WebUI should only inspect mounted workspaces. Set it only when browser users are trusted to modify those repositories from WebUI.
When the flag is enabled, branch switching parks and restores local changes automatically. If the branch being left has local changes, WebUI parks those changes in a WebUI-owned Git stash, switches branches, and then restores any WebUI-owned stash for the branch being entered. If Git cannot restore the stash cleanly, WebUI leaves the stash in place and reports the restore failure instead of dropping it.
Workspace and path scope
The browser does not send an arbitrary repository path. Git requests carry a session id and, when needed, workspace-relative file paths. The server resolves the session workspace, checks each path against that workspace, and then builds Git pathspecs from the checked paths.
Git commands run through subprocess.run with shell=False. Local status and diff commands use a 5
second timeout. Remote operations such as fetch, pull, and push use a 60 second timeout.
Before any Git subprocess starts, WebUI removes inherited GIT_DIR, GIT_WORK_TREE,
GIT_CONFIG_GLOBAL, GIT_CONFIG_SYSTEM, GIT_CONFIG_COUNT, GIT_CONFIG_PARAMETERS, and injected
GIT_CONFIG_KEY_* / GIT_CONFIG_VALUE_* values from the environment. Those variables can redirect
Git to a different repository or inject config, so WebUI does not trust them from the parent process.
GIT_INDEX_FILE is the intentional exception. Selected-file commits use a temporary index so WebUI
can commit only the requested files, then remove the temporary index afterward.
Coordination with active runs
Mutating Git actions are rejected while the same session has a live stream. The API returns
active_stream instead of racing a running agent that may be writing files in the same workspace.
Mutating Git actions also take a per-repository lock. If another Git mutation is already running for
that repository, the API returns operation_in_progress.
Hook and remote behavior
WebUI does not bypass Git hooks. Hook code may come from .git/hooks/ or from a configured
core.hooksPath.
Commit actions run normal commit hooks such as pre-commit, commit-msg, and post-commit. Push can
run pre-push. Pull uses --ff-only, so it does not create a merge commit, but it is still a Git
operation running under the WebUI process.
Push keeps Git's normal non-fast-forward protection and reports non-fast-forward rejection separately from general Git failures.
If a hook fails, the API returns a structured Git error instead of hiding the failure. Other classified failures include authentication errors, missing upstream branches, conflicts, dirty worktrees, invalid refs, missing Git binaries, and timeouts.