Closed-loop reflection / skill creation agent on LangGraph + deepagents. Faithful reproduction of Nous Research's Hermes Agent.
Project description
langstage-hermes
A faithful reproduction of Nous Research's Hermes Agent on top of LangGraph + deepagents + langgraph-stream-parser.
Status: live on PyPI (renamed from deepagent-hermes — the old name now just installs this one, and the deepagent-hermes command still works). Spec at SPEC.md. Release notes in CHANGELOG.md. The runtime is verified end-to-end against a real Anthropic model — both the memory loop and the skill-creation loop close autonomously; see examples/dogfood.py and examples/dogfood_procedural.py for the traces.
What it is
A deepagents-built agent with a closed reflection→skill-creation loop:
- After ~10 tool-using iterations, a review subagent runs in the background, writes/patches a
SKILL.mdcapturing the pattern it just exercised, and ships it to a skill library. - Next session, the agent reads the library at startup, sees the new skill's description in its system prompt, and can
skill_view(name)to load the full body on demand (progressive disclosure per the agentskills.io spec). - A weekly curator consolidates skills into umbrellas and archives stale ones.
- A frozen-snapshot memory (
MEMORY.md+USER.md) preserves prefix-cache hits for the entire session. - FTS5 session search indexes every past conversation in a local SQLite DB.
- Bundled MarkdownProvider that keyword-searches
<HERMES_HOME>/memories/notes/*.md— drop hand-authored long-form context there and the agent surfaces relevant sections on demand. Zero external dependencies.
Designed to be loaded into the LangStage host family without UI changes — set LANGSTAGE_AGENT_SPEC=langstage_hermes.agent:graph in any of them.
Every stage for your LangGraph agent
langstage-hermes is the reference agent of the LangStage family: write your agent once — any LangGraph CompiledGraph — and run it on every stage with the same spec string (module:attr or path/to/file.py:attr), the same langstage.toml config file, and the same LANGSTAGE_* environment variables.
| Stage | Package | Try it |
|---|---|---|
| Web app | langstage | langstage run --agent langstage_hermes.agent:graph |
| JupyterLab | langstage-jupyter | pip install langstage-jupyter, then the chat sidebar in jupyter lab |
| Terminal | langstage-cli | langstage-cli -a langstage_hermes.agent:graph |
| VS Code | langstage-vscode | chat participant + stdio sidecar |
| Reference agent | langstage-hermes | you are here |
| Shared core | langgraph-stream-parser | typed events + config resolver behind every stage |
Serve over AG-UI
This surface's agent — any LangGraph CompiledGraph — can also be served over the AG-UI protocol. Install the extra and point the bundled console script at your agent spec:
pip install "langgraph-stream-parser[agui]"
langstage-agui --agent langstage_hermes.agent:graph
📖 Full documentation: https://dkedar7.github.io/langstage-docs/
Installation
pip install langstage-hermes
Or with uv (recommended):
uv venv .venv
. .venv/Scripts/activate # Windows
. .venv/bin/activate # macOS / Linux
uv pip install langstage-hermes
Optional extras
pip install "langstage-hermes[openai]" # OpenAI / OpenRouter / any OpenAI-wire provider
pip install "langstage-hermes[daytona]" # Daytona sandbox terminal backend
pip install "langstage-hermes[modal]" # Modal sandbox terminal backend
pip install "langstage-hermes[ssh]" # paramiko-backed SSH terminal backend
pip install "langstage-hermes[dev]" # tests + lint (contributors only)
Picking a model
By default the agent uses anthropic:claude-sonnet-4-5-20250929 and needs ANTHROPIC_API_KEY set. Swap the model via --model on the CLI or model.default in langstage-hermes.toml — any init_chat_model string works.
OpenAI / OpenRouter
pip install "langstage-hermes[openai]"
export OPENAI_API_KEY=sk-… # or: OPENROUTER_API_KEY=sk-or-v1-…
export OPENAI_BASE_URL=https://openrouter.ai/api/v1 # only for OpenRouter
langstage-hermes chat --model openai:openai/gpt-4o-mini
For OpenRouter specifically you usually also want:
export LANGSTAGE_HERMES_MODEL_DEFAULT="openai:openai/gpt-4o-mini"
export LANGSTAGE_HERMES_MODEL_AUX="openai:openai/gpt-4o-mini"
so the reflection subagent uses the same cheap model.
Verify your setup
langstage-hermes verify
does one live round-trip against the configured model and confirms the prompts, bundled skills, and FTS5 store all wire up correctly. Run this first on any fresh install — if it passes, chat will work.
Quick start
# show resolved config + sources
langstage-hermes --show-config
# interactive chat
langstage-hermes chat
# chat against a different agent (same spec format as every LangStage
# stage; overrides LANGSTAGE_AGENT_SPEC)
langstage-hermes chat -a my_agent.py:graph
# from inside chat:
# /skills list available skills
# /model anthropic:claude-haiku-4-5-20251001 switch models
# /memory dump current memory snapshot
# /compress force context compression
# /quit
Load into an existing host
Any LangStage host can run this agent:
# langstage-cli
LANGSTAGE_AGENT_SPEC="langstage_hermes.agent:graph" langstage-cli
# langstage-jupyter — set the same in langstage.toml under [agent]
echo 'spec = "langstage_hermes.agent:graph"' >> langstage.toml
langstage-jupyter
Configuration
langstage-hermes.toml (project) or ~/.langstage-hermes/config.toml (global). Layered resolution: defaults < TOML < LANGSTAGE_HERMES_* env < CLI overrides. See SPEC §2 for every field; langstage-hermes --show-config prints the resolved value + source of each.
Architecture
See SPEC.md for the full 21-section requirements doc. Top-level layout:
src/langstage_hermes/agent.py— the compiled graph (entry point for hosts)src/langstage_hermes/config.py—HermesConfig(HostConfig)resolversrc/langstage_hermes/state.py—HermesState(extendsAgentState)src/langstage_hermes/reflection.py— closed-loop middleware + review subagentsrc/langstage_hermes/skills/— SkillLibrary, loader, toolssrc/langstage_hermes/memory/— frozen-snapshot memory + provider ABCsrc/langstage_hermes/store/sqlite_fts.py—BaseStorewith FTS5src/langstage_hermes/search/session_search.py—session_searchtoolsrc/langstage_hermes/compression.py—HermesCompressionMiddlewaresrc/langstage_hermes/caching.py—AnthropicCachingS3Middlewaresrc/langstage_hermes/budget.py—IterationBudgetMiddlewaresrc/langstage_hermes/tools/— registry + 33 toolsets + 6 terminal envssrc/langstage_hermes/cron/— daemon +cronjobtoolsrc/langstage_hermes/plugins/— discovery + lifecycle hookssrc/langstage_hermes/cli.py—langstage-hermesentry pointprompts/— verbatim/paraphrased system-prompt building blocks
Status by subsystem
| Subsystem | Status |
|---|---|
| Config + state + agent factory | ✅ working |
| Reflection loop (10-iter / 10-turn triggers, subagent review) | ✅ working — verified live |
| Skill library + agentskills.io validator | ✅ working |
| Skill loader (system-prompt injection + progressive disclosure) | ✅ working |
skill_view / skill_manage / skills_list tools |
✅ working |
| Frozen-snapshot memory (MEMORY.md / USER.md) | ✅ working — verified live (702 bytes written autonomously) |
SQLite FTS5 store + session_search (3 modes) |
✅ working |
MarkdownProvider (bundled, default) |
✅ keyword search over <HERMES_HOME>/memories/notes/*.md — zero deps |
| Iteration budget middleware | ✅ working |
| Compression middleware (13-section template) | ✅ working |
Anthropic system_and_3 caching strategy |
✅ working |
| Tool registry + 33-toolset enum | ✅ working |
LocalEnvironment terminal backend |
✅ working (Git Bash on Windows) |
DockerEnvironment |
✅ working (gated on docker info reachability) |
SshEnvironment |
✅ working (paramiko-backed, behind [ssh] extra) |
SingularityEnvironment |
✅ working (auto-detects singularity / apptainer) |
DaytonaEnvironment / ModalEnvironment |
✅ lazy SDK with defensive attribute probing (extras-gated) |
Cron daemon + cronjob tool |
✅ working (deliverers: local, stdout, agentmail) |
| Plugin loader (4 discovery sources) | ✅ working (13 of 17 lifecycle hooks wired) |
| CLI + v1-essentials slash commands | ✅ working |
| Curator (skill lifecycle) | ✅ basic |
| Bundled skills | ✅ 26 from nousresearch/hermes-agent (MIT, attributed) |
| Self-evolution integration | 📄 docs only (separate offline repo) |
License
MIT. See LICENSE. This project is a faithful reproduction of the design ideas in Nous Research's Hermes Agent — see NOTICE for attribution.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file langstage_hermes-0.3.0.tar.gz.
File metadata
- Download URL: langstage_hermes-0.3.0.tar.gz
- Upload date:
- Size: 1.3 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.15 {"installer":{"name":"uv","version":"0.11.15","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
08cc6033535f25614264956fa43d6593fc7049daf45bdcda41fb2c38cca9b225
|
|
| MD5 |
4a9dc464a01a9b4d58c278e03cf3783f
|
|
| BLAKE2b-256 |
6b5e3d80e2025b70d6ec7eb661fb97519f6ebd906ca95d35aa8b227ac5ef086a
|
File details
Details for the file langstage_hermes-0.3.0-py3-none-any.whl.
File metadata
- Download URL: langstage_hermes-0.3.0-py3-none-any.whl
- Upload date:
- Size: 1.4 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.15 {"installer":{"name":"uv","version":"0.11.15","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3e9cac5c932dc052e721ef0580118c80981748b57e06b6adbb73fd61dc940f44
|
|
| MD5 |
5c73484c7d2e74d48f56b25ced8a8264
|
|
| BLAKE2b-256 |
aa83df419069a60d5b330bc70e10c82a7d37f749084a819e36dfe5185bcdbf44
|