Skip to content
berdanakyurekPublic

About

No description, website, or topics provided.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Repository files navigation

guard-sh

A shell safety layer powered by LLMs. Every command you type is checked before it runs — risky ones require confirmation.

$ rm -rf /var/log/*
guard-sh: Deletes all files in /var/log recursively. Are you sure? [Y/n]

How it works

  1. You press Enter on a command.
  2. guard-sh intercepts it and sends it to an LLM.
  3. If the LLM considers it safe, the command runs normally.
  4. If not, you see a one-line warning and a [Y/n] prompt.
  5. Press Y to proceed, anything else to cancel.

Commands in your whitelist skip the LLM entirely.

Supported LLMs

Requirements

  • Go 1.22+
  • bash, zsh, or fish
  • API key(s) for one or more of the cloud LLMs listed above, or a running Ollama instance for fully local operation.

Installation

From source

git clone https://github.com/berdanakyurek/guard-sh.git
cd guard-sh
bash install.sh

This will:

  • Build the guard-sh binary and install it to ~/.local/bin/
  • Copy the default config to ~/.config/guard-sh/config.yaml
  • Copy the default prompt to ~/.config/guard-sh/prompt.txt
  • Add shell integration to the rc file of your active shell (bash → .bashrc, zsh → .zshrc, fish → config.fish)

From binary

Download the binary for your platform from the releases page, place it in ~/.local/bin/, then run:

chmod +x ~/.local/bin/guard-sh
guard-sh setup

This will create the config dir, write the shell integration scripts, and add them to the rc file of your active shell.

Install without shell integration

bash install.sh --without-shell

Multiple shells

install.sh and guard-sh setup only add integration for your active shell (detected via the parent process). If you use multiple shells, run the command once from each:

# In bash
bash install.sh

# In zsh
bash install.sh

# In fish
bash install.sh

Or use guard-sh setup after installing the binary:

# In bash
guard-sh setup

# Switch to zsh, then:
guard-sh setup

Uninstallation

Using the shell script

bash uninstall.sh

This removes the binary, shell integration from all rc files, and the config dir.

To keep your config (providers, whitelist, cache):

bash uninstall.sh --keep-config

Using the built-in command

guard-sh uninstall          # removes shell integration and shell scripts, keeps config
guard-sh uninstall --purge  # also removes the config dir (~/.config/guard-sh)

After running guard-sh uninstall, the binary itself is not removed (a running program cannot delete itself reliably). The command prints the path to remove manually:

next  remove the binary manually:
      rm ~/.local/bin/guard-sh

Configuration

Config file: ~/.config/guard-sh/config.yaml

  • Providers can be added interactively with guard-sh provider add — see Providers.
  • The whitelist can also be managed with guard-sh whitelist commands — see Whitelist.
  • Cache settings can also be managed with guard-sh cache — see Cache.

Or you can edit the config file manually.

An example config file is as follows:

# Providers are tried in order. If one fails, the next is used.
provider_order:
  - ollama
  - gemini
  - deepseek
  - openai
  - claude

providers:
  ollama:
    host: http://localhost:11434/api/chat # optional, this is the default
    model: llama3.2                       # optional, this is the default
  gemini:
    api_key: YOUR_GEMINI_KEY
    model: gemini-3.1-flash-lite-preview  # optional, this is the default
  deepseek:
    api_key: YOUR_DEEPSEEK_KEY
    model: deepseek-chat                  # optional, this is the default
  openai:
    api_key: YOUR_OPENAI_KEY
    model: gpt-4o-mini                    # optional, this is the default
  claude:
    api_key: YOUR_ANTHROPIC_KEY
    model: claude-haiku-4-5-20251001      # optional, this is the default

# Commands always considered safe — LLM is never called.
# Only the base command name is needed: "ls" covers "ls -la", "ls /tmp", etc.
# For chained commands (&&, ||, ;, |), ALL parts must be whitelisted.
command_whitelist:
  - ls
  - cat
  - echo
  - pwd
  - cd
  - clear

# How long to wait for an LLM response, in seconds. Defaults to 10 if not set.
timeout_seconds: 10

# Include the working directory in the command sent to the LLM.
# Allows the LLM to assess risk based on context (e.g. chmod in /etc vs ~/projects).
# Cache keys include the working directory when this is enabled.
# Set to false to send only the command string.
send_working_directory: true

# Cache LLM responses to avoid repeated API calls for the same command.
cache_enabled: true
cache_max_size: 1000

Custom prompt

The LLM prompt is stored at ~/.config/guard-sh/prompt.txt. Edit it to adjust what guard-sh considers risky, change the output format, or add your own rules. Changes take effect immediately — no rebuild needed.

Working directory context

By default, guard-sh includes the current working directory when querying the LLM. This gives the LLM context to make better decisions — for example, chmod 777 config.yaml in /etc is riskier than in ~/projects/.

The LLM receives a structured two-line query:

Working directory: /etc
Command: chmod 777 config.yaml

The working directory is also included in cache keys, so the same command in different directories is evaluated independently.

To disable:

send_working_directory: false

Redaction

guard-sh can redact sensitive values from commands before sending them to any LLM provider. Two methods are supported: pattern-based and Shannon entropy-based. Matches are replaced with [REDACTED].

Redaction is configured globally under redaction: in your config, and can be overridden per-provider under providers.NAME.redaction.

redaction:
  pattern_based:
    enabled: true
    patterns:
      - '(?i)(password|passwd|secret|api[_-]?key|token|auth)\s*[=:]\s*\S+'
      - '(?i)--password\s+\S+'
      - 'AKIA[0-9A-Z]{16}'
  shannon_entropy_based:
    enabled: false
    threshold: 4.5   # bits/char — typical English ~3.5, secrets typically >4.5
    min_length: 20   # ignore tokens shorter than this

Pattern-based redaction

Uses Go regular expressions. Any token matching a pattern is replaced with [REDACTED]. On by default for all providers.

You can add your own patterns:

redaction:
  pattern_based:
    enabled: true
    patterns:
      - '(?i)(password|passwd|secret|api[_-]?key|token|auth)\s*[=:]\s*\S+'
      - '(?i)--password\s+\S+'
      - 'AKIA[0-9A-Z]{16}'
      - 'ghp_[a-zA-Z0-9]{36}'        # GitHub personal access tokens
      - 'xox[baprs]-[a-zA-Z0-9-]+'   # Slack tokens

Toggle per-provider:

guard-sh redact list          # list all global redaction patterns
guard-sh redact pattern on    # interactively enable for a provider
guard-sh redact pattern off   # interactively disable for a provider

Shannon entropy-based redaction

Automatically detects high-entropy strings (API keys, random tokens, private key material) without requiring explicit patterns. Any whitespace-delimited token above the entropy threshold is replaced with [REDACTED]. Off by default.

Toggle per-provider:

guard-sh redact entropy on    # interactively enable for a provider
guard-sh redact entropy off   # interactively disable for a provider

Per-provider overrides

A provider can override any part of the global redaction config:

providers:
  ollama:
    host: http://localhost:11434/api/chat
    redaction:                      # optional — overrides global for this provider
      pattern_based:
        enabled: false              # disable pattern redaction for local model
  gemini:
    api_key: YOUR_KEY
    redaction:
      shannon_entropy_based:
        enabled: true
        threshold: 4.0             # more sensitive than global default
        min_length: 16

Fields not specified in the per-provider block fall back to the global value.

Provider-specific prompts

To use a different prompt for a specific provider, create prompt_PROVIDERNAME.txt in the same directory:

~/.config/guard-sh/prompt.txt           # default, used by all providers
~/.config/guard-sh/prompt_ollama.txt    # used only when ollama is queried
~/.config/guard-sh/prompt_gemini.txt    # used only when gemini is queried

If a provider-specific file exists, it takes precedence over prompt.txt for that provider.

Usage

guard-sh is designed to run as a shell integration — it intercepts every command you type automatically. Once installed, you don’t need to invoke it manually.

You can test it directly with:

guard-sh check "rm -rf /"

This is useful for testing your configuration, but normal usage happens transparently through the shell hook.

Help

guard-sh help

Lists all commands and their usage.

Session control

guard-sh on      # enable for the current session
guard-sh off     # disable for the current session

Global control

guard-sh on --global    # auto-enable in every new terminal
guard-sh off --global   # don't auto-enable in new terminals

off --global does not remove guard-sh from your shell — it only stops it from auto-enabling. You can still use guard-sh on in any terminal at any time.

Healthcheck

guard-sh healthcheck

Checks all configured providers without spending any tokens. Reports:

  • API key and model validity for cloud providers; server connectivity for Ollama
  • Response latency per provider
  • Shell integration status (.bashrc / .zshrc / config.fish)
  • Config errors (e.g. unknown provider names in provider_order)
guard-sh healthcheck

providers
ollama      llama3.2                             ● ok  (12ms)
gemini      gemini-3.1-flash-lite-preview        ● ok  (184ms)
deepseek    deepseek-chat                        ✗ HTTP 401: Authentication Fails
openai      gpt-4o-mini                          ● ok  (759ms)
claude      claude-haiku-4-5-20251001            ● ok  (510ms)

shell
bash    ~/.bashrc                      ● present
zsh     ~/.zshrc                       ○ not found
fish    ~/.config/fish/config.fish     ○ not found

Status

guard-sh status

Shows session and global state, prompt path, timeout, cache stats, active providers, redaction patterns, shell integration status, and whitelist.

guard-sh

session   ● on
global    ● on
config    ~/.config/guard-sh/config.yaml
prompt    ~/.config/guard-sh/prompt.txt
timeout   10s
work dir  ● on
cache     ● on
          1000 max entries
          42 entries, 8.3 KB

providers
1  gemini
   model                gemini-3.1-flash-lite-preview
   pattern redaction     ● on
   entropy redaction     ○ off

2  ollama
   model                llama3.2
   pattern redaction     ○ off
   entropy redaction     ○ off

3  deepseek
   model                deepseek-chat
   pattern redaction     ● on
   entropy redaction     ○ off

redaction
1  (?i)(password|passwd|secret|api[_-]?key|token|auth)\s*[=:]\s*\S+
2  (?i)--password\s+\S+
3  AKIA[0-9A-Z]{16}

shell
bash    ~/.bashrc                      ● present
zsh     ~/.zshrc                       ○ not found
fish    ~/.config/fish/config.fish     ○ not found

whitelist
1  ls
2  cat
3  echo
4  pwd
5  cd
6  clear
7  man
8  help
9  history
10  which
+3 more (to see all, run "guard-sh whitelist")

Debug mode

guard-sh check "<command>" --debug

Prints a step-by-step trace to stderr: whitelist result, per-provider cache check, redaction status, response time, and the final LLM response.

command   "rm -rf /"

whitelist ○ miss

providers
openai      pattern ○ off  unchanged
            entropy ○ off  unchanged
              ✓ ok (1315ms)

result    "This command will recursively delete everything from root."

With redaction enabled, the redacted form is shown before the query is sent:

providers
openai      pattern ● on  → "rm -rf [REDACTED]"
            entropy ○ off  unchanged
              ✓ ok (891ms)

On a cache hit, the provider is not queried at all:

providers
openai      cache ● hit  → "This command will recursively delete everything from root."

If a provider fails, guard-sh moves on to the next and shows why:

providers
openai      pattern ○ off  unchanged
            entropy ○ off  unchanged
              ✗ HTTP 429: Rate limit exceeded (234ms), trying next
gemini      pattern ○ off  unchanged
            entropy ○ off  unchanged
              ✓ ok (401ms)

Setup

guard-sh setup

Creates ~/.config/guard-sh/ with the default config and prompt, writes shell integration scripts (bash, zsh, fish), and adds them to your rc file based on your current shell. Existing files are not overwritten. This is the only step needed after downloading a pre-built binary.

Version

guard-sh version

Prints the current version (e.g. 1.0.0).

Providers

guard-sh provider add      # interactively add a provider
guard-sh provider remove   # interactively remove a provider
guard-sh provider order    # interactively reorder providers

provider add walks you through selecting a provider, picking a model, and entering an API key (or a full chat endpoint URL for Ollama, e.g. http://localhost:11434/api/chat). The provider is saved to your config and added to provider_order automatically.

provider remove lists your configured providers and removes the one you select.

provider order opens an interactive list. Use arrow keys to navigate, Enter to grab a provider, arrow keys to move it, Enter again to place it. s saves and exits, q exits without saving.

Whitelist

Commands in the whitelist are always safe. The LLM is never called.

command_whitelist:
  - ls
  - git
  • ls, ls -la, ls /tmp → all pass instantly
  • ls && rm -rf / → rm is not whitelisted, so the full command goes to the LLM
  • For chained commands, all parts must be whitelisted to skip the LLM

You can manage the whitelist from the command line:

guard-sh whitelist              # list all whitelisted commands
guard-sh whitelist add git      # add a command
guard-sh whitelist remove git   # remove a command

Cache

guard-sh caches LLM responses locally so the same command is never sent to the API twice. The cache is stored at ~/.config/guard-sh/cache.json.

When the cache is full, the least recently used entries are evicted first.

cache_enabled: true    # set to false to disable caching
cache_max_size: 1000   # max number of cached responses

You can also toggle caching from the command line:

guard-sh cache on           # enable caching
guard-sh cache off          # disable caching
guard-sh cache size 500     # set max cache size
guard-sh cache clear        # delete all cached responses

Shell support

ShellMechanism
bashshopt -s extdebug + DEBUG trap
zshZLE widget bound to Enter
fishbind \n~/\r~ mapped to custom function

License

GNU General Public License v3.0 — see LICENSE.

About

No description, website, or topics provided.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages