mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-04-28 23:11:37 +08:00
Compare commits
1 Commits
opencode-p
...
hermes/her
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
22eb259ff4 |
@@ -57,6 +57,15 @@ metadata:
|
||||
hermes:
|
||||
tags: [Category, Subcategory, Keywords]
|
||||
related_skills: [other-skill-name]
|
||||
requires_toolsets: [web] # Optional — only show when these toolsets are active
|
||||
requires_tools: [web_search] # Optional — only show when these tools are available
|
||||
fallback_for_toolsets: [browser] # Optional — hide when these toolsets are active
|
||||
fallback_for_tools: [browser_navigate] # Optional — hide when these tools exist
|
||||
required_environment_variables: # Optional — env vars the skill needs
|
||||
- name: MY_API_KEY
|
||||
prompt: "Enter your API key"
|
||||
help: "Get one at https://example.com"
|
||||
required_for: "API access"
|
||||
---
|
||||
|
||||
# Skill Title
|
||||
@@ -91,6 +100,57 @@ platforms: [windows] # Windows only
|
||||
|
||||
When set, the skill is automatically hidden from the system prompt, `skills_list()`, and slash commands on incompatible platforms. If omitted or empty, the skill loads on all platforms (backward compatible).
|
||||
|
||||
### Conditional Skill Activation
|
||||
|
||||
Skills can declare dependencies on specific tools or toolsets. This controls whether the skill appears in the system prompt for a given session.
|
||||
|
||||
```yaml
|
||||
metadata:
|
||||
hermes:
|
||||
requires_toolsets: [web] # Hide if the web toolset is NOT active
|
||||
requires_tools: [web_search] # Hide if web_search tool is NOT available
|
||||
fallback_for_toolsets: [browser] # Hide if the browser toolset IS active
|
||||
fallback_for_tools: [browser_navigate] # Hide if browser_navigate IS available
|
||||
```
|
||||
|
||||
| Field | Behavior |
|
||||
|-------|----------|
|
||||
| `requires_toolsets` | Skill is **hidden** when ANY listed toolset is **not** available |
|
||||
| `requires_tools` | Skill is **hidden** when ANY listed tool is **not** available |
|
||||
| `fallback_for_toolsets` | Skill is **hidden** when ANY listed toolset **is** available |
|
||||
| `fallback_for_tools` | Skill is **hidden** when ANY listed tool **is** available |
|
||||
|
||||
**Use case for `fallback_for_*`:** Create a skill that serves as a workaround when a primary tool isn't available. For example, a `duckduckgo-search` skill with `fallback_for_tools: [web_search]` only shows when the web search tool (which requires an API key) is not configured.
|
||||
|
||||
**Use case for `requires_*`:** Create a skill that only makes sense when certain tools are present. For example, a web scraping workflow skill with `requires_toolsets: [web]` won't clutter the prompt when web tools are disabled.
|
||||
|
||||
### Environment Variable Requirements
|
||||
|
||||
Skills can declare environment variables they need. When a skill is loaded via `skill_view`, its required vars are automatically registered for passthrough into sandboxed execution environments (terminal, execute_code).
|
||||
|
||||
```yaml
|
||||
required_environment_variables:
|
||||
- name: TENOR_API_KEY
|
||||
prompt: "Tenor API key" # Shown when prompting user
|
||||
help: "Get your key at https://tenor.com" # Help text or URL
|
||||
required_for: "GIF search functionality" # What needs this var
|
||||
```
|
||||
|
||||
Each entry supports:
|
||||
- `name` (required) — the environment variable name
|
||||
- `prompt` (optional) — prompt text when asking the user for the value
|
||||
- `help` (optional) — help text or URL for obtaining the value
|
||||
- `required_for` (optional) — describes which feature needs this variable
|
||||
|
||||
Users can also manually configure passthrough variables in `config.yaml`:
|
||||
|
||||
```yaml
|
||||
terminal:
|
||||
env_passthrough:
|
||||
- MY_CUSTOM_VAR
|
||||
- ANOTHER_VAR
|
||||
```
|
||||
|
||||
See `skills/apple/` for examples of macOS-only skills.
|
||||
|
||||
## Secure Setup on Load
|
||||
|
||||
@@ -55,6 +55,22 @@ Settings are resolved in this order (highest priority first):
|
||||
Secrets (API keys, bot tokens, passwords) go in `.env`. Everything else (model, terminal backend, compression settings, memory limits, toolsets) goes in `config.yaml`. When both are set, `config.yaml` wins for non-secret settings.
|
||||
:::
|
||||
|
||||
## Environment Variable Substitution
|
||||
|
||||
You can reference environment variables in `config.yaml` using `${VAR_NAME}` syntax:
|
||||
|
||||
```yaml
|
||||
auxiliary:
|
||||
vision:
|
||||
api_key: ${GOOGLE_API_KEY}
|
||||
base_url: ${CUSTOM_VISION_URL}
|
||||
|
||||
delegation:
|
||||
api_key: ${DELEGATION_KEY}
|
||||
```
|
||||
|
||||
Multiple references in a single value work: `url: "${HOST}:${PORT}"`. If a referenced variable is not set, the placeholder is kept verbatim (`${UNDEFINED_VAR}` stays as-is). Only the `${VAR}` syntax is supported — bare `$VAR` is not expanded.
|
||||
|
||||
## Inference Providers
|
||||
|
||||
You need at least one way to connect to an LLM. Use `hermes model` to switch providers and models interactively, or configure directly:
|
||||
@@ -1329,6 +1345,23 @@ Usage: type `/status`, `/disk`, `/update`, or `/gpu` in the CLI or any messaging
|
||||
- **Type** — only `exec` is supported (runs a shell command); other types show an error
|
||||
- **Works everywhere** — CLI, Telegram, Discord, Slack, WhatsApp, Signal, Email, Home Assistant
|
||||
|
||||
## Gateway Streaming
|
||||
|
||||
Enable progressive token delivery on messaging platforms. When streaming is enabled, responses appear character-by-character in Telegram, Discord, and Slack via message editing, rather than waiting for the full response.
|
||||
|
||||
```yaml
|
||||
streaming:
|
||||
enabled: false # Enable streaming token delivery (default: off)
|
||||
transport: edit # "edit" (progressive message editing) or "off"
|
||||
edit_interval: 0.3 # Min seconds between message edits
|
||||
buffer_threshold: 40 # Characters accumulated before forcing an edit
|
||||
cursor: " ▉" # Cursor character shown during streaming
|
||||
```
|
||||
|
||||
**Platform support:** Telegram, Discord, and Slack support edit-based streaming. Platforms that don't support message editing (Signal, Email, Home Assistant) are auto-detected on the first attempt — streaming is gracefully disabled for that session with no flood of messages.
|
||||
|
||||
**Overflow handling:** If the streamed text exceeds the platform's message length limit (~4096 chars), the current message is finalized and a new one starts automatically.
|
||||
|
||||
## Human Delay
|
||||
|
||||
Simulate human-like response pacing in messaging platforms:
|
||||
@@ -1350,6 +1383,27 @@ code_execution:
|
||||
max_tool_calls: 50 # Max tool calls within code execution
|
||||
```
|
||||
|
||||
## Web Search Backends
|
||||
|
||||
The `web_search`, `web_extract`, and `web_crawl` tools support three backend providers. Configure the backend in `config.yaml` or via `hermes tools`:
|
||||
|
||||
```yaml
|
||||
web:
|
||||
backend: firecrawl # firecrawl | parallel | tavily
|
||||
```
|
||||
|
||||
| Backend | Env Var | Search | Extract | Crawl |
|
||||
|---------|---------|--------|---------|-------|
|
||||
| **Firecrawl** (default) | `FIRECRAWL_API_KEY` | ✔ | ✔ | ✔ |
|
||||
| **Parallel** | `PARALLEL_API_KEY` | ✔ | ✔ | — |
|
||||
| **Tavily** | `TAVILY_API_KEY` | ✔ | ✔ | ✔ |
|
||||
|
||||
**Backend selection:** If `web.backend` is not set, the backend is auto-detected from available API keys. If only `TAVILY_API_KEY` is set, Tavily is used. If only `PARALLEL_API_KEY` is set, Parallel is used. Otherwise Firecrawl is the default.
|
||||
|
||||
**Self-hosted Firecrawl:** Set `FIRECRAWL_API_URL` to point at your own instance. When a custom URL is set, the API key becomes optional (set `USE_DB_AUTHENTICATION=false` on the server to disable auth).
|
||||
|
||||
**Parallel search modes:** Set `PARALLEL_SEARCH_MODE` to control search behavior — `fast`, `one-shot`, or `agentic` (default: `agentic`).
|
||||
|
||||
## Browser
|
||||
|
||||
Configure browser automation behavior:
|
||||
|
||||
109
website/docs/user-guide/features/context-references.md
Normal file
109
website/docs/user-guide/features/context-references.md
Normal file
@@ -0,0 +1,109 @@
|
||||
---
|
||||
sidebar_position: 9
|
||||
title: "Context References"
|
||||
description: "Inline @-syntax for attaching files, folders, git diffs, and URLs directly into your messages"
|
||||
---
|
||||
|
||||
# Context References
|
||||
|
||||
Type `@` followed by a reference to inject content directly into your message. Hermes expands the reference inline and appends the content under an `--- Attached Context ---` section.
|
||||
|
||||
## Supported References
|
||||
|
||||
| Syntax | Description |
|
||||
|--------|-------------|
|
||||
| `@file:path/to/file.py` | Inject file contents |
|
||||
| `@file:path/to/file.py:10-25` | Inject specific line range (1-indexed, inclusive) |
|
||||
| `@folder:path/to/dir` | Inject directory tree listing with file metadata |
|
||||
| `@diff` | Inject `git diff` (unstaged working tree changes) |
|
||||
| `@staged` | Inject `git diff --staged` (staged changes) |
|
||||
| `@git:5` | Inject last N commits with patches (max 10) |
|
||||
| `@url:https://example.com` | Fetch and inject web page content |
|
||||
|
||||
## Usage Examples
|
||||
|
||||
```text
|
||||
Review @file:src/main.py and suggest improvements
|
||||
|
||||
What changed? @diff
|
||||
|
||||
Compare @file:old_config.yaml and @file:new_config.yaml
|
||||
|
||||
What's in @folder:src/components?
|
||||
|
||||
Summarize this article @url:https://arxiv.org/abs/2301.00001
|
||||
```
|
||||
|
||||
Multiple references work in a single message:
|
||||
|
||||
```text
|
||||
Check @file:main.py, and also @file:test.py.
|
||||
```
|
||||
|
||||
Trailing punctuation (`,`, `.`, `;`, `!`, `?`) is automatically stripped from reference values.
|
||||
|
||||
## CLI Tab Completion
|
||||
|
||||
In the interactive CLI, typing `@` triggers autocomplete:
|
||||
|
||||
- `@` shows all reference types (`@diff`, `@staged`, `@file:`, `@folder:`, `@git:`, `@url:`)
|
||||
- `@file:` and `@folder:` trigger filesystem path completion with file size metadata
|
||||
- Bare `@` followed by partial text shows matching files and folders from the current directory
|
||||
|
||||
## Line Ranges
|
||||
|
||||
The `@file:` reference supports line ranges for precise content injection:
|
||||
|
||||
```text
|
||||
@file:src/main.py:42 # Single line 42
|
||||
@file:src/main.py:10-25 # Lines 10 through 25 (inclusive)
|
||||
```
|
||||
|
||||
Lines are 1-indexed. Invalid ranges are silently ignored (full file is returned).
|
||||
|
||||
## Size Limits
|
||||
|
||||
Context references are bounded to prevent overwhelming the model's context window:
|
||||
|
||||
| Threshold | Value | Behavior |
|
||||
|-----------|-------|----------|
|
||||
| Soft limit | 25% of context length | Warning appended, expansion proceeds |
|
||||
| Hard limit | 50% of context length | Expansion refused, original message returned unchanged |
|
||||
| Folder entries | 200 files max | Excess entries replaced with `- ...` |
|
||||
| Git commits | 10 max | `@git:N` clamped to range [1, 10] |
|
||||
|
||||
## Security
|
||||
|
||||
### Sensitive Path Blocking
|
||||
|
||||
These paths are always blocked from `@file:` references to prevent credential exposure:
|
||||
|
||||
- SSH keys and config: `~/.ssh/id_rsa`, `~/.ssh/id_ed25519`, `~/.ssh/authorized_keys`, `~/.ssh/config`
|
||||
- Shell profiles: `~/.bashrc`, `~/.zshrc`, `~/.profile`, `~/.bash_profile`, `~/.zprofile`
|
||||
- Credential files: `~/.netrc`, `~/.pgpass`, `~/.npmrc`, `~/.pypirc`
|
||||
- Hermes env: `$HERMES_HOME/.env`
|
||||
|
||||
These directories are fully blocked (any file inside):
|
||||
- `~/.ssh/`, `~/.aws/`, `~/.gnupg/`, `~/.kube/`, `$HERMES_HOME/skills/.hub/`
|
||||
|
||||
### Path Traversal Protection
|
||||
|
||||
All paths are resolved relative to the working directory. References that resolve outside the allowed workspace root are rejected.
|
||||
|
||||
### Binary File Detection
|
||||
|
||||
Binary files are detected via MIME type and null-byte scanning. Known text extensions (`.py`, `.md`, `.json`, `.yaml`, `.toml`, `.js`, `.ts`, etc.) bypass MIME-based detection. Binary files are rejected with a warning.
|
||||
|
||||
## Error Handling
|
||||
|
||||
Invalid references produce inline warnings rather than failures:
|
||||
|
||||
| Condition | Behavior |
|
||||
|-----------|----------|
|
||||
| File not found | Warning: "file not found" |
|
||||
| Binary file | Warning: "binary files are not supported" |
|
||||
| Folder not found | Warning: "folder not found" |
|
||||
| Git command fails | Warning with git stderr |
|
||||
| URL returns no content | Warning: "no content extracted" |
|
||||
| Sensitive path | Warning: "path is a sensitive credential file" |
|
||||
| Path outside workspace | Warning: "path is outside the allowed workspace" |
|
||||
@@ -358,6 +358,42 @@ When a blocked URL is requested, the tool returns an error explaining the domain
|
||||
|
||||
See [Website Blocklist](/docs/user-guide/configuration#website-blocklist) in the configuration guide for full details.
|
||||
|
||||
### SSRF Protection
|
||||
|
||||
All URL-capable tools (web search, web extract, vision, browser) validate URLs before fetching them to prevent Server-Side Request Forgery (SSRF) attacks. Blocked addresses include:
|
||||
|
||||
- **Private networks** (RFC 1918): `10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`
|
||||
- **Loopback**: `127.0.0.0/8`, `::1`
|
||||
- **Link-local**: `169.254.0.0/16` (includes cloud metadata at `169.254.169.254`)
|
||||
- **CGNAT / shared address space** (RFC 6598): `100.64.0.0/10` (Tailscale, WireGuard VPNs)
|
||||
- **Cloud metadata hostnames**: `metadata.google.internal`, `metadata.goog`
|
||||
- **Reserved, multicast, and unspecified addresses**
|
||||
|
||||
SSRF protection is always active and cannot be disabled. DNS failures are treated as blocked (fail-closed). Redirect chains are re-validated at each hop to prevent redirect-based bypasses.
|
||||
|
||||
### Tirith Pre-Exec Security Scanning
|
||||
|
||||
Hermes integrates [tirith](https://github.com/sheeki03/tirith) for content-level command scanning before execution. Tirith detects threats that pattern matching alone misses:
|
||||
|
||||
- Homograph URL spoofing (internationalized domain attacks)
|
||||
- Pipe-to-interpreter patterns (`curl | bash`, `wget | sh`)
|
||||
- Terminal injection attacks
|
||||
|
||||
Tirith auto-installs from GitHub releases on first use with SHA-256 checksum verification (and cosign provenance verification if cosign is available).
|
||||
|
||||
```yaml
|
||||
# In ~/.hermes/config.yaml
|
||||
security:
|
||||
tirith_enabled: true # Enable/disable tirith scanning (default: true)
|
||||
tirith_path: "tirith" # Path to tirith binary (default: PATH lookup)
|
||||
tirith_timeout: 5 # Subprocess timeout in seconds
|
||||
tirith_fail_open: true # Allow execution when tirith is unavailable (default: true)
|
||||
```
|
||||
|
||||
When `tirith_fail_open` is `true` (default), commands proceed if tirith is not installed or times out. Set to `false` in high-security environments to block commands when tirith is unavailable.
|
||||
|
||||
Tirith's verdict integrates with the approval flow: safe commands pass through, suspicious commands trigger user approval, and dangerous commands are blocked.
|
||||
|
||||
### Context File Injection Protection
|
||||
|
||||
Context files (AGENTS.md, .cursorrules, SOUL.md) are scanned for prompt injection before being included in the system prompt. The scanner checks for:
|
||||
|
||||
@@ -114,7 +114,13 @@ Session IDs follow the format `YYYYMMDD_HHMMSS_<8-char-hex>`, e.g. `20250305_091
|
||||
|
||||
Give sessions human-readable titles so you can find and resume them easily.
|
||||
|
||||
### Setting a Title
|
||||
### Auto-Generated Titles
|
||||
|
||||
Hermes automatically generates a short descriptive title (3–7 words) for each session after the first exchange. This runs in a background thread using a fast auxiliary model, so it adds no latency. You'll see auto-generated titles when browsing sessions with `hermes sessions list` or `hermes sessions browse`.
|
||||
|
||||
Auto-titling only fires once per session and is skipped if you've already set a title manually.
|
||||
|
||||
### Setting a Title Manually
|
||||
|
||||
Use the `/title` slash command inside any chat session (CLI or gateway):
|
||||
|
||||
|
||||
Reference in New Issue
Block a user