Overview
Skills that wrap external services often need API keys to function. Currently, there's no way for a skill to declare its requirements, and no secure mechanism to collect credentials when they're needed.
This enhancement adds a requires.env section to skill frontmatter that declares environment variables. When the skill is loaded at runtime — either by the agent calling skill_view() or the user invoking a /skill command — the system checks for missing env vars and triggers a secure TUI prompt (identical to the sudo password widget) to collect them. Keys are written to ~/.hermes/.env, never exposed in LLM chat context or session logs.
Design
Skill Frontmatter requires.env Section
---
name: my-service-skill
description: Integrate with SomeService API
version: 1.0.0
metadata:
hermes:
tags: [api, integration]
requires:
env:
- key: SOME_API_KEY
prompt: "SomeService API key"
url: "https://someservice.com/account/api-keys"
- key: SOME_PROJECT_ID
prompt: "SomeService project ID"
url: "https://someservice.com/projects"
---
Runtime Trigger (Primary UX)
When a skill with requires.env is loaded and an env var is missing, the TUI shows a secure input widget — same pattern as sudo password entry:
╭─ 🔑 API Key Required ──────────────────────────────────────╮
│ │
│ Skill 'my-service' requires: SOME_API_KEY │
│ SomeService API key │
│ Get one at: https://someservice.com/account/api-keys │
│ │
│ Enter key below (hidden), or press Enter to skip │
╰─────────────────────────────────────────────────────────────╯
🔑 > ********
✓ Saved to ~/.hermes/.env
How it works (mirrors sudo password exactly):
skill_view() parses frontmatter, finds requires.env
- Checks each key against
os.environ / ~/.hermes/.env
- If missing: sets
cli._secret_state = {"key": "...", "prompt": "...", "url": "...", "response_queue": Queue()}
- TUI renders a
ConditionalContainer with masked input (same as sudo widget at cli.py:3193-3217)
- User types key (hidden) or presses Enter to skip
- Key written to
~/.hermes/.env, loaded into os.environ
skill_view() callback resolves, returns skill content
Key Behaviors
-
Secure by design — Keys use the TUI masked input widget. Never flows through LLM chat context, tool results, or session logs. Written directly to ~/.hermes/.env.
-
Skippable — User can press Enter to skip. The skill loads but the agent is told: "Note: SOME_API_KEY is not configured. This skill's functionality will be limited. The user can set it in ~/.hermes/.env or reload the skill to be prompted again."
-
One-time — Once saved to .env, subsequent skill loads find the key and skip the prompt. Persists across sessions.
-
Sequential — If multiple keys are required, prompt them one at a time.
-
Gateway fallback — For Telegram/Discord users (no TUI), display a message: "⚠️ Skill requires SOME_API_KEY. Please add it to ~/.hermes/.env on your server, then try again." No attempt to collect secrets through chat.
-
Install-time convenience — hermes skills install can also check requires.env and prompt via getpass.getpass() (CLI mode, no TUI needed). This is secondary — the runtime prompt catches anything missed.
Implementation Plan
Phase 1: Core env var prompting
- Parse
requires.env from skill YAML frontmatter
- New callback:
secret_input_callback(cli, key, prompt, url) in hermes_cli/callbacks.py
- New TUI widget:
ConditionalContainer for _secret_state in cli.py
- Integration in
skill_view(): check env vars, invoke callback if missing
- Write to
~/.hermes/.env on success
Phase 2: Install-time + doctor
hermes skills install also prompts for missing env vars after confirmation
hermes doctor reports installed skills with missing requirements
hermes skills configure <name> — re-prompt for an installed skill's env vars
Phase 3: Runtime awareness
- When building the skill index for the system prompt, annotate skills with unmet requirements:
"⚠️ requires SOME_API_KEY" next to the skill description
- Agent can see at a glance which skills are fully configured vs. missing keys
Existing Patterns to Build On
| Component |
File |
Pattern |
| Sudo password widget |
cli.py:3193-3217 |
_sudo_state, ConditionalContainer, masked input |
| Sudo password callback |
callbacks.py:63-101 |
response_queue, blocking, skip on Enter |
| Secure CLI input |
tools_config.py:41-55 |
getpass.getpass() for non-TUI context |
| .env writing |
tools_config.py:660-700 |
Reading/writing ~/.hermes/.env |
| Skill frontmatter parsing |
skills_tool.py |
YAML frontmatter extraction |
Use Cases
| Skill |
Env Vars Needed |
| Browserbase |
BROWSERBASE_API_KEY, BROWSERBASE_PROJECT_ID |
| Google Workspace (#411) |
GOOGLE_WORKSPACE_* |
| ElevenLabs TTS |
ELEVENLABS_API_KEY |
| Notion |
NOTION_API_KEY |
| ml.ink (#495) |
INK_API_KEY |
| Any service-wrapping skill |
Service credentials |
Scope Boundaries
This issue is only about env var requirements and secure prompting. MCP server auto-configuration (discovering tools, adding MCP entries to config.yaml, selective tool loading) is tracked separately in the MCP Server Management issue.
References
Overview
Skills that wrap external services often need API keys to function. Currently, there's no way for a skill to declare its requirements, and no secure mechanism to collect credentials when they're needed.
This enhancement adds a
requires.envsection to skill frontmatter that declares environment variables. When the skill is loaded at runtime — either by the agent callingskill_view()or the user invoking a/skillcommand — the system checks for missing env vars and triggers a secure TUI prompt (identical to the sudo password widget) to collect them. Keys are written to~/.hermes/.env, never exposed in LLM chat context or session logs.Design
Skill Frontmatter
requires.envSectionRuntime Trigger (Primary UX)
When a skill with
requires.envis loaded and an env var is missing, the TUI shows a secure input widget — same pattern as sudo password entry:How it works (mirrors sudo password exactly):
skill_view()parses frontmatter, findsrequires.envos.environ/~/.hermes/.envcli._secret_state = {"key": "...", "prompt": "...", "url": "...", "response_queue": Queue()}ConditionalContainerwith masked input (same as sudo widget atcli.py:3193-3217)~/.hermes/.env, loaded intoos.environskill_view()callback resolves, returns skill contentKey Behaviors
Secure by design — Keys use the TUI masked input widget. Never flows through LLM chat context, tool results, or session logs. Written directly to
~/.hermes/.env.Skippable — User can press Enter to skip. The skill loads but the agent is told:
"Note: SOME_API_KEY is not configured. This skill's functionality will be limited. The user can set it in ~/.hermes/.env or reload the skill to be prompted again."One-time — Once saved to
.env, subsequent skill loads find the key and skip the prompt. Persists across sessions.Sequential — If multiple keys are required, prompt them one at a time.
Gateway fallback — For Telegram/Discord users (no TUI), display a message:
"⚠️ Skill requires SOME_API_KEY. Please add it to ~/.hermes/.env on your server, then try again."No attempt to collect secrets through chat.Install-time convenience —
hermes skills installcan also checkrequires.envand prompt viagetpass.getpass()(CLI mode, no TUI needed). This is secondary — the runtime prompt catches anything missed.Implementation Plan
Phase 1: Core env var prompting
requires.envfrom skill YAML frontmattersecret_input_callback(cli, key, prompt, url)inhermes_cli/callbacks.pyConditionalContainerfor_secret_stateincli.pyskill_view(): check env vars, invoke callback if missing~/.hermes/.envon successPhase 2: Install-time + doctor
hermes skills installalso prompts for missing env vars after confirmationhermes doctorreports installed skills with missing requirementshermes skills configure <name>— re-prompt for an installed skill's env varsPhase 3: Runtime awareness
"⚠️ requires SOME_API_KEY"next to the skill descriptionExisting Patterns to Build On
cli.py:3193-3217_sudo_state,ConditionalContainer, masked inputcallbacks.py:63-101response_queue, blocking, skip on Entertools_config.py:41-55getpass.getpass()for non-TUI contexttools_config.py:660-700~/.hermes/.envskills_tool.pyUse Cases
BROWSERBASE_API_KEY,BROWSERBASE_PROJECT_IDGOOGLE_WORKSPACE_*ELEVENLABS_API_KEYNOTION_API_KEYINK_API_KEYScope Boundaries
This issue is only about env var requirements and secure prompting. MCP server auto-configuration (discovering tools, adding MCP entries to config.yaml, selective tool loading) is tracked separately in the MCP Server Management issue.
References
hermes_cli/callbacks.py:63-101— Sudo password callback (the pattern to follow)cli.py:3193-3217— Sudo password TUI widget