.github
ci: run the WhatsApp bridge node tests in the JS & TS job
acp_adapter
fix(delegation): stopping a turn no longer kills background subagents
agent
chore(skills): move niche built-in skills to optional
apps
fix(webapp): picker rows resolve their menu on open; focus returns to the picker
assets
feat(icons): custom drive artwork as the volume icon of both installer DMGs
contributors
docs(providers): add Modular model-provider plugin to catalog
cron
fix(cron): grace_minutes=0 skips real misses instead of every run
docker
fix(docker): declare the sourced profile.d script's shell for shellcheck
evals
test(cron): the fork-race probe waits for killed descendants to exit
gateway
fix(tui_gateway): Bot Chat streaming never shows or speaks a closing silence marker
hermes_cli
fix(plugins): quoted /proc redirects stay writes; own-module from-imports stop warning
hermes_platform
refactor(desktop): find vswhere through hermes_platform
locales
chore(i18n): regenerate the desktop key manifest for zones.tabActions
native
fix activation of devenv, use /usr/bin/env bash everywhere
nix
feat(nix): pass the token as HERMES_DASHBOARD_SESSION_TOKEN=file:<path>
optional-mcps
chore(catalog): drop the optional-mcps entry; Runa lists as a plugin (the MCP catalog takes no new entries)
optional-skills
refactor(skills): fold docx, powerpoint and xlsx into one microsoft-office skill
plugin-catalog
fix(plugins): clear catalog sweep 1028 scanner false positives and close three validator gaps
plugins
refactor: the Discord approval card retires through the views' shared embed stamp
pm
fix(skills): document skills share one PM-built side environment; pause before Enter in the no-tmux recipe
providers
fix(providers): a home rescan never re-imports a hosted provider plugin it already loaded
scripts
ci: run the WhatsApp bridge node tests in the JS & TS job
skills
fix(skills): keep nested-table order and table column names intact
tests
fix(plugins): quoted /proc redirects stay writes; own-module from-imports stop warning
tests-js
perf(webapp): build the browser bundle without downloading Electron
tools
fix(plugins): quoted /proc redirects stay writes; own-module from-imports stop warning
tui_gateway
fix(tui_gateway): Bot Chat streaming never shows or speaks a closing silence marker
ui-tui
fix(cli,tui): a stalled event loop no longer submits a held Enter ahead of a waiting paste chunk
web
fix(web): isolate PostCSS discovery from ancestor config
website
fix(plugins): clear catalog sweep 1028 scanner false positives and close three validator gaps
.coderabbit.yaml
ci: version the required check so CI greens from before a new required job stop counting
.dockerignore
fix(docker): hermes webapp reuses the baked bundle, and local Desktop files stay out of the image
.env.example
docs(browser): drop references to deleted browser tools
.envrc
fix(direnv): watch nix/ and pm/ recursively
.gitattributes
fix(release): close publication custody gaps
.gitignore
fix(agent): the agent's file tools and profile clones leave the Webapp's sign-in files alone
.hadolint.yaml
feat(docker): remove gosu from bundled image; s6-setuidgid handles privilege drop
.mailmap
chore: mailmap kshitijkapoorr@gmail.com to kshitijk4poor's canonical noreply
.npmrc
fix(deps): pin Electron 44.9.3 and drop the 40.10.2-era install config
.nvmrc
feat: add .nvmrc w/ node 26
.prettierignore
fix(ci): js-autofix pushes via PR instead of direct push to main (#65186)
.prettierrc
refactor(lint): hoist shared eslint + prettier config to root
.python-version
feat(python): move first-party runtime to 3.14; swap wake engine to pyopen-wakeword
activate
feat(activate): add activate.fish for the fish shell
activate.fish
feat(activate): add activate.fish for the fish shell
activate.ps1
feat(pm): isolate developer test environment from runtime extras
AGENTS.md
docs: root AGENTS.md becomes a hub; area rules move where they load
batch_runner.py
refactor: move the Singularity terminal backend out of core into the singularity catalog plugin
cli-config.yaml.example
fix(bedrock): apply configured request timeouts to Bedrock clients
cli.py
feat(config): remote config backend (HERMES_CONFIG_BACKEND=remote)
CONTRIBUTING.es.md
chore(memory): holographic leaves core for its community catalog plugin (re-land #136424)
CONTRIBUTING.md
chore(skills): move niche built-in skills to optional
docker-compose.windows.yml
feat(docker): add Windows Docker Desktop compatible compose file
docker-compose.yml
docs(compose): update entrypoint comment for s6-overlay
Dockerfile
refactor(skills): fold docx, powerpoint and xlsx into one microsoft-office skill
eslint.config.shared.mjs
fix(ci): eslint ignores *.generated.ts; restore the contract file's header
flake.lock
chore(nix): nix flake update
flake.nix
feat(nix): home-manager module, shared with the NixOS module
hermes
fix: use argparse entrypoint in top-level launcher (#3874)
hermes_bootstrap.py
ci: UP007, UP022, UP028, UP031, UP041 linter fixes
hermes_constants_scratch_detach.py
fix(scratch): the detached prune spares the launcher's whole ancestry and fails closed
hermes_constants_scratch_stuck.py
fix(scratch): stuck-entry records recover from nested fixes, survive concurrent pruners
hermes_constants_scratch.py
fix(process-identity): old-format ledger entries keep main's epoch match
hermes_constants.py
fix(scratch): run the due scratch prune in a detached child so it always finishes
hermes_dir_acl.py
refactor(windows): one TokenElevation probe for grants, refusal naming and the service installer
hermes_logging.py
feat(config): route every user config.yaml read and write through a ConfigBackend seam
hermes_startup_watchdog.py
ci: ruff UP037 fixes
hermes_state_api_content.py
fix(sessions): proactive prune rewrites only the changed rows, in place (#124273)
hermes_state_common.py
fix(cli): a session with a pending first admission is not an empty launch stub
hermes_state_compaction_display.py
fix(state): a compacted tool result paints once, as its archived original
hermes_state_compression.py
fix(sessions): refresh epoch survives compression rotation; --session targets the tip
hermes_state_coverage.py
fix(state): a dedupe claim needs the occurrence, its version and its replay bytes
hermes_state_dbfile.py
fix(state): recognise old FTS layouts by name; stamp only the exact current one
hermes_state_detached_results.py
refactor(state): move the detached-result writers out of hermes_state_messages
hermes_state_errors.py
fix(sessions): proactive prune rewrites only the changed rows, in place (#124273)
hermes_state_fts.py
fix(sessions): optimize-storage paces for a writer that opens state.db mid-run; failed runs exit 1
hermes_state_gateway.py
fix(state): session reads on the gateway loop never wait on the token writer
hermes_state_guard.py
ci: ruff UP037 fixes
hermes_state_health.py
ci: apply all automatic linter fixes available
hermes_state_holders.py
ci: apply all automatic linter fixes available
hermes_state_identity.py
ci: apply all automatic linter fixes available
hermes_state_ids.py
docs(state): trim derived-id recognizer comments to the contract
hermes_state_keys.py
fix(cron): pair output docs with attempts after sessions are known
hermes_state_local_lineage.py
fix(gateway): commit a local receipt's compression catch-up off the owner loop
hermes_state_local_migration.py
fix(webapp): every stored owner is read by one rule, so old Webapp chats open and adopt again
hermes_state_local.py
perf(state): reuse unchanged local lineage projections
hermes_state_lockguard.py
ci: apply all automatic linter fixes available
hermes_state_lockowners.py
ci: apply all automatic linter fixes available
hermes_state_maintenance.py
fix(plugins): on_session_delete review findings
hermes_state_media.py
fix(tools): spill pointers in structured content and Windows paths count as references (#126351)
hermes_state_messages.py
chore(state): name the weak claim at both rewind sites; hoist the per-message import; replay through substitute_api_content
hermes_state_mutation_binding.py
fix(webapp): every stored owner is read by one rule, so old Webapp chats open and adopt again
hermes_state_mutation_branch.py
fix(state): a branch of an ACP session starts at the Default edit mode
hermes_state_mutation_chat_pick.py
fix: fence a messaging chat pick with a mutation receipt and revision bump
hermes_state_mutation_compress.py
fix(compress): report the canonical /compress outcome like native /compress
hermes_state_mutation_guards.py
fix(gateway,desktop): keep compression busy refusals at debug, share the busy mapping, check the reason on Desktop
hermes_state_mutation_prepared.py
fix(gateway): keep a deferred level across a direct model pick; show it in Desktop
hermes_state_mutation_reset.py
fix(state): exclude workers across the complete conversation lineage
hermes_state_mutation_retirement.py
fix(gateway): fence a route whose retirement value is not valid JSON
hermes_state_mutation_transcript.py
feat: reuse transactional rewind with generation and receipt fences
hermes_state_mutations.py
fix(acp): refuse a non-string edit policy as invalid_params
hermes_state_pidns.py
refactor(state): hoist pidns imports and trim duplicated call-site prose
hermes_state_portability.py
feat(plugins): on_session_delete covers Desktop deletes and deliberate archives
hermes_state_profile_repair.py
feat(plugins): on_session_delete covers Desktop deletes and deliberate archives
hermes_state_prompt_refresh.py
feat(sessions): refresh-prompts lets continuing sessions adopt updated prompt sources
hermes_state_prune_rewrite.py
fix(agent): a tool-row rewrite commits only while this process owns the turn
hermes_state_readpool.py
fix: core modules import again on Python 3.11-3.13 (re-quote eager forward references)
hermes_state_reconcile.py
chore(sessions): meet code-health on the round-3 browse catch-up
hermes_state_registry.py
ci: ruff UP037 fixes
hermes_state_repair.py
fix(state): a WAL sidecar unlinked mid-preflight is gone, not read-only
hermes_state_rewind.py
fix(gateway): /retry's rewrite commits in its re-send's own admission
hermes_state_runtime_workers.py
fix(managed-worker): delegated children build, close and settle off Relay's loop
hermes_state_runtime.py
fix(desktop): a retry refused because its id is already admitted settles as delivered
hermes_state_schema.py
fix(state): keep the store opening when the realign meets a trigram index without its tokenizer
hermes_state_search.py
fix(sessions): optimize-storage counts backfill rows from an index; no VACUUM over a live writer
hermes_state_session_list.py
fix(sessions): pin the page-first list contract, keep the facade under its cap
hermes_state_sessions_model_config.py
fix: what the main merge left broken outside its conflict hunks
hermes_state_sessions.py
fix(state): session reads on the gateway loop never wait on the token writer
hermes_state_telegram.py
ci: apply all automatic linter fixes available
hermes_state_terminal.py
fix(desktop): a retry refused because its id is already admitted settles as delivered
hermes_state_timeline.py
fix(state): a compacted tool result paints once, as its archived original
hermes_state_titles.py
fix(state): never transfer a title off a parent across a branch edge
hermes_state_todo.py
fix(state): a Todo plan undone in a compression child stays gone on an omitted resume
hermes_state_usage.py
fix(state): session reads on the gateway loop never wait on the token writer
hermes_state_user_copy.py
fix(agent): user copy for the session_row_missing persistence cause
hermes_state_wal.py
Merge origin/main (#27: 19 commits to 517b5e10feb) into feat/unified-gateway-runtime
hermes_state_worker_compression.py
fix(state): a compacted tool result paints once, as its archived original
hermes_state_worker_context.py
fix(delegation): managed workers accept the tool pin's delegation_backend
hermes_state_worker_lifecycle.py
fix(managed-worker): delegated children build, close and settle off Relay's loop
hermes_state.py
feat(sessions): refresh-prompts lets continuing sessions adopt updated prompt sources
hermes_time.py
docs(config): document HERMES_CONFIG_BACKEND; correct the hermes_time fallback comment
hermes_yaml.py
ci: fix PLC0206, PLC0414 linter errors
justfile
chore: pin specific js dependency versions
lefthook.yml
chore(hooks): web lint hook no longer grabs website/ files
LICENSE
fix: restore missing MIT license file
mini_swe_runner.py
ci: RUF013, RUF015
model_tools.py
feat(config): route every user config.yaml read and write through a ConfigBackend seam
package-lock.json
chore(deps): keep three at 0.180.0
package.json
chore(node): require Node >=26
pyproject.toml
fix(skills): document skills share one PM-built side environment; pause before Enter in the no-tmux recipe
README.es.md
refactor: OpenClaw migration leaves core too; first-time setup offers the agent-importers plugin
README.md
refactor: OpenClaw migration leaves core too; first-time setup offers the agent-importers plugin
README.ur-pk.md
refactor: OpenClaw migration leaves core too; first-time setup offers the agent-importers plugin
README.zh-CN.md
refactor: OpenClaw migration leaves core too; first-time setup offers the agent-importers plugin
registration_lifecycle.py
ci: ruff UP037 fixes
ruff.pre-commit.toml
ci: don't enforce CC in pre commit
ruff.toml
ci: limit python cyclomatic complexity to pre-commit hook
run_agent.py
fix(gateway): join delegations in the turn when interim messages are off
SECURITY.es.md
feat: consolidate 'hermes version' into 'hermes --version', remove the subcommand
SECURITY.md
feat: consolidate 'hermes version' into 'hermes --version', remove the subcommand
setup-hermes.ps1
fix(install): preserve Unicode Python paths in developer setup
setup-hermes.sh
fix(install): request the native bootstrap Python on Windows-on-ARM
setup.py
refactor(pm): own group-only builds and finish dependency hints
SOUL.md
refactor(skills): shipped-set slim — 15 to optional, github 6-way merge, pdf absorbs OCR, channel-gated teams pipeline (index −26%) (#98539)
toolset_distributions.py
ci: apply all automatic linter fixes available
toolsets.py
fix(gateway): join delegations in the turn when interim messages are off
trajectory_compressor.py
ci: fix remaining ASYNCXXX linter errors
utils.py
fix(cache): a file that stats but cannot be read keys a real read, never raises from the digest
uv.lock
fix(skills): document skills share one PM-built side environment; pause before Enter in the no-tmux recipe

Hermes Agent ☤

Hermes Agent | Hermes Desktop

The self-improving AI agent built by Nous Research. It's the only agent with a built-in learning loop — it creates skills from experience, improves them during use, nudges itself to persist knowledge, searches its own past conversations, and builds a deepening model of who you are across sessions. Run it on a $5 VPS, a GPU cluster, or serverless infrastructure that costs nearly nothing when idle. It's not tied to your laptop — talk to it from Telegram while it works on a cloud VM.

Use any model you want — Nous Portal, OpenRouter, OpenAI, your own endpoint, and many others. Switch with hermes model — no code changes, no lock-in.

A real terminal interfaceFull TUI with multiline editing, slash-command autocomplete, conversation history, interrupt-and-redirect, and streaming tool output.
Lives where you doTelegram, Discord, Slack, WhatsApp, Signal, and CLI — all from a single gateway process. Voice memo transcription, cross-platform conversation continuity.
A closed learning loopAgent-curated memory with periodic nudges. Autonomous skill creation after complex tasks. Skills self-improve during use. FTS5 session search with LLM summarization for cross-session recall. Honcho dialectic user modeling. Compatible with the agentskills.io open standard.
Scheduled automationsBuilt-in cron scheduler with delivery to any platform. Daily reports, nightly backups, weekly audits — all in natural language, running unattended.
Delegates and parallelizesSpawn isolated subagents for parallel workstreams. In Desktop, choose their provider, model, and limits under Settings → Model → Subagents, then Apply the complete route. Write Python scripts that call tools via RPC, collapsing multi-step pipelines into zero-context-cost turns.
Runs anywhere, not just your laptopSix built-in terminal backends — local, Docker, SSH, Modal, Daytona, and Vercel Sandbox — plus plugin backends such as Singularity/Apptainer. Daytona and Modal offer serverless persistence — your agent's environment hibernates when idle and wakes on demand, costing nearly nothing between sessions. Run it on a $5 VPS or a GPU cluster.
Research-readyBatch trajectory generation, trajectory compression for training the next generation of tool-calling models.

Quick Install

Linux, macOS, WSL2

curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash

Windows (native, PowerShell)

Heads up: Native Windows runs Hermes without WSL — CLI, gateway, TUI, and tools all work natively. If you'd rather use WSL2, the Linux/macOS one-liner above works there too. Found a bug? Please file issues.

Run this in PowerShell:

iex (irm https://hermes-agent.nousresearch.com/install.ps1)

The source installer delegates Python 3.14, Node.js, npm, ripgrep, FFmpeg, and Python dependencies to PM. If Git is absent, it stages the verified Git for Windows archive in Hermes' tool store. It does not replace your system Git. See installation methods for the separate MSIX/App Installer package and its update ownership.

Android / Termux: A signed APT repository is available for aarch64 devices, with a stable channel (tagged releases) and a prerelease canary channel. The package includes Python, Node.js, and the TUI. Use the Termux guide, not the desktop/server installer script.

Windows: Native Windows is fully supported — the PowerShell one-liner above installs everything. If you'd rather use WSL2, the Linux command works there too. Native Windows install lives under %LOCALAPPDATA%\hermes; WSL2 installs under ~/.hermes as on Linux.

After installation:

source ~/.bashrc    # reload shell (or: source ~/.zshrc)
hermes              # start chatting!

Troubleshooting

Windows Defender or antivirus flags uv.exe as malware

If your antivirus (Bitdefender, Windows Defender, etc.) quarantines uv.exe from the Hermes bin folder (%LOCALAPPDATA%\hermes\bin\uv.exe), this is a false positive. The file is Astral's uv — the Rust Python package manager Hermes bundles to manage its Python environment. ML-based antivirus engines commonly flag unsigned Rust binaries that download and install packages.

To verify your copy is authentic:

# Install GitHub CLI if needed
winget install --id GitHub.cli

# Login to GitHub
gh auth login

# Run verification
$uv = "$env:LOCALAPPDATA\hermes\bin\uv.exe"
$ver = (& $uv --version).Split(' ')[1]
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$zip = "$env:TEMP\uv.zip"
Invoke-WebRequest "https://github.com/astral-sh/uv/releases/download/$ver/uv-x86_64-pc-windows-msvc.zip" -OutFile $zip -UseBasicParsing
gh attestation verify $zip --repo astral-sh/uv
Expand-Archive $zip "$env:TEMP\uv_x" -Force
(Get-FileHash "$env:TEMP\uv_x\uv.exe").Hash -eq (Get-FileHash $uv).Hash

If attestation says "Verification succeeded" and the last line prints True, you're good.

To whitelist Hermes:

  • Windows Defender: Run PowerShell as Admin → Add-MpPreference -ExclusionPath "$env:LOCALAPPDATA\hermes\bin"
  • Bitdefender: Add an exception in the Bitdefender console (Protection > Antivirus > Settings > Manage Exceptions)
  • Whitelist the folder, not the file hash — Hermes updates uv and the hash changes every version

For more context, see the upstream Astral reports: astral-sh/uv#13553, astral-sh/uv#15011, astral-sh/uv#10079.


Getting Started

hermes              # Interactive CLI — start a conversation
hermes model        # Choose your LLM provider and model
hermes tools        # Configure which tools are enabled
hermes config set   # Set individual config values
hermes config get   # Print individual config values
hermes gateway      # Start the messaging gateway (Telegram, Discord, etc.)
hermes setup        # Run the full setup wizard (configures everything at once)
hermes update       # Update to the latest version
hermes doctor       # Diagnose any issues

📖 Full documentation →


Skip the API-key collection — Nous Portal

Hermes works with whatever provider you want — that's not changing. But if you'd rather not collect five separate API keys for the model, web search, image generation, TTS, and a cloud browser, Nous Portal covers all of them under one subscription:

  • 300+ models — pick any of them with /model <name>
  • Tool Gateway — web search, image generation (FAL), text-to-speech (OpenAI), cloud browser (Browser Use), all routed through your sub. No extra accounts.

One command from a fresh install:

hermes setup --portal

That logs you in via OAuth, sets Nous as your provider, and turns on the Tool Gateway. Check what's wired up any time with hermes portal info. Full details on the Tool Gateway docs page.

You can still bring your own keys per-tool whenever you want — the gateway is per-backend, not all-or-nothing.


CLI vs Messaging Quick Reference

Hermes has two entry points: start the terminal UI with hermes, or run the gateway and talk to it from Telegram, Discord, Slack, WhatsApp, Signal, or Email. Once you're in a conversation, many slash commands are shared across both interfaces.

ActionCLIMessaging platforms
Start chattinghermesRun hermes gateway setup + hermes gateway start, then send the bot a message
Start fresh conversation/new or /reset/new or /reset
Change model/model [provider:model]/model [provider:model]
Set a personality/personality [name]/personality [name]
Retry or undo the last turn/retry, /undo/retry, /undo
Compress context / check usage/compress, /usage, /insights [--days N]/compress, /usage, /insights [days]
Browse skills/skills or /<skill-name>/<skill-name>
Interrupt current workCtrl+C or send a new message/stop or send a new message
Platform-specific status/platforms/status, /sethome

For the full command lists, see the CLI guide and the Messaging Gateway guide.


Documentation

All documentation lives at hermes-agent.nousresearch.com/docs:

SectionWhat's Covered
QuickstartInstall → setup → first conversation in 2 minutes
CLI UsageCommands, keybindings, personalities, sessions
ConfigurationConfig file, providers, models, all options
Messaging GatewayTelegram, Discord, Slack, WhatsApp, Signal, Home Assistant
SecurityCommand approval, DM pairing, container isolation
Tools & Toolsets40+ tools, toolset system, terminal backends
Skills SystemProcedural memory, Skills Hub, creating skills
MemoryPersistent memory, user profiles, best practices
MCP IntegrationConnect any MCP server for extended capabilities
Cron SchedulingScheduled tasks with platform delivery
Context FilesProject context that shapes every conversation
ArchitectureProject structure, agent loop, key classes
ContributingDevelopment setup, PR process, code style
CLI ReferenceAll commands and flags
Environment VariablesComplete env var reference

Migrating from OpenClaw or another agent

If you're coming from OpenClaw, Claude Code, Codex CLI or Cursor, Hermes can import your settings, memories and skills (and, for OpenClaw, API keys when you ask for them).

During setup: hermes setup asks whether to import from another agent, pre-selects the ones it finds (~/.openclaw, ~/.claude, ~/.codex, ~/.cursor), installs the official agent-importers plugin and runs the import with a preview first.

Anytime after install:

hermes plugins install agent-importers          # once per profile
hermes import-agent openclaw                    # interactive migration (full preset)
hermes import-agent openclaw --dry-run          # preview what would be migrated
hermes import-agent openclaw --migrate-secrets  # also bring allowlisted API keys
hermes import-agent claude-code                 # or codex / cursor

What gets imported from OpenClaw:

  • SOUL.md — persona file
  • Memories — MEMORY.md and USER.md entries
  • Skills — user-created skills → ~/.hermes/skills/openclaw-imports/
  • Command allowlist — approval patterns
  • Messaging settings — platform configs, allowed users, working directory
  • API keys — allowlisted secrets (Telegram, OpenRouter, OpenAI, Anthropic, ElevenLabs), only with --migrate-secrets
  • TTS assets — workspace audio files
  • Workspace instructions — AGENTS.md (with --workspace-target)

hermes claw migrate still works as the older spelling. See the OpenClaw migration guide and Import from Other Agents.


Contributing

We welcome contributions! See the Contributing Guide for development setup, code style, and PR process.

Start with the PM developer workflow for activation, daily use, dependency changes, and leaving the environment. Development Setup covers the separate test environment and verification commands.


Community

  • 💬 Discord
  • 📚 Skills Hub
  • 🐛 Issues
  • 🔌 computer-use-linux — Linux desktop-control MCP server for Hermes and other MCP hosts, with AT-SPI accessibility trees, Wayland/X11 input, screenshots, and compositor window targeting.
  • 🔌 HermesClaw — Community WeChat bridge: Run Hermes Agent and OpenClaw on the same WeChat account.

License

MIT — see LICENSE.

Built by Nous Research.