AI-dev library · Atlas

Hermes Agent

Nous Research's self-improving personal agent OS: one agent that lives on a server, talks to you from any messaging app, runs shell commands anywhere, and teaches itself skills after every job.

nousresearch/hermes-agentHEAD 2446c8bread 2026-08-09 84 tools · 59 toolsets77+114 skills22+ platforms33 model providers7 terminal backends

What it is

Hermes is a whole agent in one box: the body (a gateway process that answers Telegram, Discord, WhatsApp, Signal and ~20 more, plus a terminal UI and a desktop app) and the brain (memory files, a skill library, and a searchable record of every conversation) ship together. It runs on your machine or a $5 server, uses any of 33 model providers, and — its signature trick — after each turn it quietly asks itself should I save a memory or write a skill from what just happened? in a side process that never touches your conversation. The whole design is organized around one rule: never break the prompt cache. Everything expensive stays out of the model's context window unless it has earned its place there.

Legend: in-context lives inside the model's window — paid on every API call out-of-band runs outside the window — costs nothing per turn

Glossary map

shared termHermes calls itwhere
brainmemory (MEMORY.md-style files) + one SQLite state.dbtools/memory_tool.py · hermes_state.py
skillskill (agentskills.io standard)skills/ · tools/skills_tool.py
intake fanthe gateway: ~30 platform adapters → one process → one session storegateway/run.py
filing gatethreat-pattern scans that block writes to memory, cron, and skill installstools/threat_patterns.py
query pathsession search — keyword-only FTS5, zero LLM callstools/session_search_tool.py
night shiftthe curator — idle-triggered (weekly + 2h idle), not nightlyagent/curator.py
consolidationoverflow-triggered memory merging; opt-in curator skill consolidationagent/curator.py
pruningarchive — almost nothing truly deleteshermes_state.py
meta layerbackground review fork + /learn + curator: skills making skillsagent/background_review.py

Body vs brain

Unusually, this repo is both. The body: gateway, TUI, desktop app, ACP for IDEs, an MCP server, seven terminal backends. The brain: memory files, skills, FTS5 recall. What is not in the box: the models (any provider), and optionally Honcho — an external user-modeling service that plugs in as one of eight swappable memory providers.

One honest caveat

The price of the cache-first constitution is a repo of god-files (cli.py is 870 KB, run_agent.py 380 KB) — known debt, not a goal. And the default install runs agent commands directly on your machine: SECURITY.md says plainly that the OS, not the agent, is the only real boundary. There is also no local dollar cap — spend is capped in iterations and characters, never USD.

Key decisions

The repo rendered as answers to the canonical register — Core (C#), Memory bank (M#), plus two DRAFT questions it answers unusually well.

C1

Source of truth

Chose: plain files the user owns under ~/.hermesconfig.yaml for behavior, .env for secrets only, Markdown memory, skill folders — plus one SQLite state.db for every transcript. Profiles are separate HERMES_HOME dirs.

Why: profiles are independent islands on purpose — a PR coupling them was closed for exactly that.

Trade-off: no hosted sync; portability is a migration command, not a service.

C2

Trust & safety boundaries

Chose: radical honesty. The only security boundary against an adversarial LLM is the operating system. Every in-process screen is officially a heuristic. Real rails: OS/container isolation, default-deny allowlists at every network surface, salted-hash DM pairing.

Why: a denylist over a Turing-complete shell is structurally incomplete — so don't pretend otherwise.

Trade-off: the default local backend runs on the host; untrusted input there is declared outside the supported posture.

C3

Cost model

Chose: no single spend cap — six layered caps, each for a different runaway shape: iteration budget (500/turn), tool-result character budgets, compression at 50% of window, opt-in loop circuit-breakers, a 429-amplification guard, provider-side credit caps. Cap #0 is the constitution itself: never invalidate the prompt cache.

Why: cache reuse multiplies the user's cost when broken.

Trade-off: nothing locally caps dollars per day.

C4

Integration surface

Chose: many bodies, one agent. One AIAgent class serves CLI, gateway, ACP, batch, and API server. Platform differences live in the entry point, not the agent. The dashboard doesn't rebuild chat in React — it embeds the real terminal UI over a PTY.

Why: anything added to the TUI shows up in the dashboard automatically.

Trade-off: the shared core grew into god-files; the PTY trick is POSIX-only.

C5

Extension model

Chose: the Footprint Ladder — extend existing → CLI command + skill → gated tool → plugin → curated MCP catalog → new core tool last. Third-party product plugins and new memory providers are closed out of the tree; they ship as standalone repos.

Why: We are expansive at the edges and conservative at the waist; in-tree vendor code is our burden to keep working against a fast-moving core.

Trade-off: capability arrives less ergonomically (a skill + shell, not a typed tool), and out-of-tree plugins lose discoverability.

C6 · draft

Honesty discipline

Chose: a prompt-text rail shipped to every session: the deliverable is a working artifact backed by real tool output — not a description of one… NEVER substitute plausible-looking fabricated output. Extra scaffolding for GPT/Grok models that declare done without verifying. Contributor side: if you can't point to the exact line where the bug manifests… you haven't verified the premise.

Trade-off: it's all prose — no machine-checked evidence gate. The one structural exception: computer-use returns a driver-verified effect verdict the model may not override.

F9 · draft

Untrusted-content boundary

Chose: framing over filtering. Web/browser/MCP results get wrapped in untrusted-data delimiters (embedded fake delimiters neutralized); hostile chat names are JSON-quoted at the gateway. Hard blocking is reserved for surfaces the user can't intervene on: context files, memory writes, cron prompts, skill installs. Strongest move: capability removal — the webhook toolset is just 4 read-only tools.

Why: it changes how the model interprets the content rather than relying on regex… catching every payload.

Trade-off: prompt injection per se is declared out of bug-bounty scope; only chained outcomes count.

M1

Storage & index

Chose: the core brain is two Markdown files (agent notes + user profile) with hard character caps, plus one SQLite file holding every session, indexed by three trigger-maintained FTS5 tables. Eight pluggable external providers (Honcho, mem0, …), max one active.

Why: character caps because char counts are model-independent; local-first, no service dependency.

Trade-off: ~1,300 tokens of curated memory total — tiny by design.

M2

Unit of memory

Chose: a free-text entry split by a § delimiter. No IDs, no timestamps, no embeddings — edits address entries by substring.

Why: the file is small enough that the agent is the index.

Trade-off: no dedup machinery; curation is the model's job, forced by the cap (see M8).

M3

Schema & typing

Chose: schemaless memory; typed everything else. Skills carry agentskills.io frontmatter (name ≤64, description effectively ≤60 chars); sessions live in a migrated SQLite schema with provenance ordering (derived < llm < user) so a model can never overwrite a title you typed.

Trade-off: memory can't be queried structurally — that's what session search and providers are for.

M4

Ingestion & capture

Chose: agent-curated writes during the turn, plus a post-turn background review fork. The famous periodic nudges are not injected text — they're counters (10 user turns without a memory write; 10 tool iterations without a skill write) that trigger the fork. A filing gate strict-scans every entry because it enters the system prompt.

Why: a poisoned entry persists for the entire session and across sessions.

Trade-off: human review of writes is opt-in, not default.

M5

Linking & structure

Chose: deliberately flat. No typed graph, no backlinks — memory entries are prose; skills structure knowledge as folders (SKILL.md + references/). Relationship modeling is outsourced to Honcho's peer cards when you want it.

Trade-off: "who works where"-style hops need an external provider; the built-in brain can't follow arrows.

M6

Retrieval stack

Chose: keyword-only, zero LLM. FTS5 + BM25 with hand-tuned rank surgery: kanban/subagent sessions hidden, cron sessions demoted (their repetitive vocabulary caused "recall blindness", starving out real conversations), compaction payloads stripped. Model-invoked only — never fires automatically.

Why: No LLM calls anywhere — every shape returns actual messages from the DB. ~20ms, free.

Trade-off: no semantic recall in the core; the README's "LLM summarization" claim is stale (removed in PR #27590).

M7

Compile vs retrieve

Chose: both sides of the fork, split by kind: compiled understanding goes into skills (how-to) and the memory snapshot (who-you-are); retrieval stays raw — full transcripts searchable forever. The bridge: compacted turns leave the model's window but stay flagged discoverable, so compression never shrinks the brain.

Why: memory captures who the user is; skills capture how to do this class of task for this user.

M8

Consolidation & maintenance

Chose: consolidation at the moment of overflow: a full memory file returns an error that instructs the agent to merge and retry in the same turn — no auto-compaction ever. Skills get the curator: inactivity-triggered (weekly, after 2h idle), deterministic stale→archive transitions; its LLM consolidation pass is opt-in and off.

Why: silent dropping is worse than a visible squeeze.

Trade-off: a turn occasionally spends effort housekeeping instead of answering.

M9

Forgetting & pruning

Chose: almost nothing deletes. The curator's maximum destructive action is archive (restorable, agent-created skills only, pinned exempt). Compaction soft-archives rows (active=0) that stay searchable. Real DELETE exists only behind user-typed commands with dry-runs.

Why: Zero uses is absence of evidence, not proof the skill is disposable.

Trade-off: the store only grows; shrinking is a chore the user owns.

The life of one message

Nine steps, from a ping on your phone to a smarter agent. Gold = touches the context window; verdigris = runs outside it.

1The front door

Every platform — Telegram, Discord, WhatsApp, Signal, email, ~30 surfaces in all — funnels into one gateway process (the intake fan). A message first hits an authorization ladder that ends in default deny; strangers can earn entry only through DM pairing: an 8-char code, salted-hashed, rate-limited, approved by the operator, never by the sender. Authorized messages get a session key — one canonical string that decides which cached agent, and whose history, this message joins.

Telegram Discord WhatsApp Signal · email …22 plugin + native gateway one process authz ladder allowlists → pairing → default DENY unknown sender → dropped session key DMs never share
The intake fan: ~30 adapters, one gateway, one gate. Authorization ends in default deny; the session key formula guarantees DMs are isolated per person ("cross-user history bleed" is the named bug it prevents).

2The frozen prompt

At session start, Hermes assembles the system prompt once: persona, the memory files as a frozen snapshot, a skills index (each description cut at 60 chars), and the narrow-waist core tool schemas. Then it never touches it again — a memory saved on turn 3 lands on disk instantly but stays invisible until next session. That's the constitution: a byte-stable prefix means the provider's prompt cache pays for every later turn.

persona + rules MEMORY.md + USER.md ❄ snapshot skills index · 60-char descriptions core tool schemas (narrow waist) frozen at session start cached prefix every turn reuses the prefix memory write, turn 3 → disk, immediately visible next session
Mid-session writes are durable but deferred: disk now, prompt next session. The one sanctioned exception to prefix stability is context compression (step 7).
  • agent/prompt_builder.py in-context — assembly; also strict-scans context files (a hostile AGENTS.md is replaced with [BLOCKED]).
  • tools/memory_tool.py in-context — the two-file brain; hard char caps, overflow refuses instead of dropping.
  • toolsets.py:31 in-context_HERMES_CORE_TOOLS: the narrow waist, edited once for all platforms.
  • tools/tool_search.py in-context — progressive disclosure: 3,300 Cloudflare MCP tools become three bridge tools.
  • agent/memory_manager.py out-of-band — external providers sync off-thread; a wedged provider can't block teardown.

3The turn loop

One turn = a loop of model call → tool calls → results appended → model call again, up to 500 iterations with a one-shot "grace call" so the model can still say goodbye after the budget dies. Mid-flight you have three verbs, each preserving message alternation differently: interrupt breaks the loop, steer rides your note in on the last tool result without stopping anything, redirect cancels only the in-flight model request and replays with your correction as a real user message.

model callstreaming tool calls tool dispatch→ step 4 guards results appended · ≤500 iterations + 1 grace no tool calls reply interrupt steer appends to last tool result — never a fake user msg redirect cancels in-flight call only
Three interrupt verbs, three insertion points — each chosen to keep role alternation legal and the cached prefix intact.

4The guard chain

Every shell command walks an ordered chain — and the order is the design. The hardline blocklist (wipe disk, power off) and user deny rules fire before yolo mode, so "I trust the agent" never means "let it reformat the box." Below yolo sit ~90 dangerous-pattern regexes with real anti-obfuscation work, then an LLM guard that reads the command inside XML delimiters. Sandboxed backends skip the whole chain: the container is the boundary — which is the honest posture, because everything in-process is officially heuristic.

command hardlinerm -rf / · mkfs user denyoperator globs yolo?→ approve allowlist→ approve ~90 patternsheuristic · deobfuscated LLM guardcmd in ⟨delimiters⟩ human approvestimeout = deny run sandboxed backend? skip everything — the container is the boundary (Docker only if no host mounts) hard rails — fire BEFORE yolo
Solid boxes are hard rails; dashed boxes are heuristics the project itself refuses to call boundaries. Gateway approval buttons re-check who clicked; silence is deny — Silence is not consent.
  • tools/approval.py in-context — 3,900 lines: the chain, NFKC/deobfuscation variants, parser limits that fail closed.
  • agent/file_safety.py in-context — read/write deny list (~/.ssh, .env, …), symlink-resolved.
  • agent/redact.py out-of-band — token masking applied to tool output before it reaches the model.
  • tools/url_safety.py out-of-band — SSRF policy; cloud-metadata IPs blocked unconditionally.
  • tools/environments/local.py:531 out-of-band — two-tier env scrubbing; every spawn site grep-able via inherit_credentials=True.

5Fanning out

Big jobs leave the parent's context. Subagents get a fresh conversation and return only a summary — the parent never sees their tool calls. Script tool-calling goes further: the model writes a Python script that calls Hermes tools over RPC; intermediate results never enter any context window, only stdout returns, and those iterations are refunded to the budget. Underneath, seven terminal backends run the actual commands — on serverless ones, files hibernate, processes don't.

parent contextsees call + result only delegate_task subagent ×3fresh context · blocked: memory, clarify, send summary only execute_code python scriptcalls 7 tools via RPC socket stdout only · iterations refunded backends: localdockersshsingularitymodaldaytonavercel ❄ files persist, processes die
Two escapes from the context window: fresh-context children (summary comes back) and script tool-calling (stdout comes back). Serverless backends snapshot the filesystem between sessions — that's what "hibernation" means.
  • tools/delegate_tool.py out-of-band — child agents; each blocked tool has a stated reason (no recursive delegation, no memory writes in the parent's name…).
  • tools/code_execution_tool.py out-of-band — "Programmatic Tool Calling": UDS locally, file-based RPC on remote backends.
  • tools/async_delegation.py out-of-band — background children surface as a new turn, never spliced mid-conversation.
  • tools/environments/ out-of-band — the seven backends behind one ABC; snapshot stores keyed by task.
  • tools/terminal_tool.py:1637 out-of-band — backend factory; teardown happens outside the lock so a slow Modal can't stall everyone.

6The learning loop

This is the headline feature, and it's cheaper than it sounds. Two counters tick silently: 10 user turns without a memory write, or 10 tool iterations without a skill write. When one trips, the turn finishes normally — then a daemon-thread fork replays the conversation snapshot and asks itself what's worth keeping. The fork can only touch memory and skill tools; everything else is denied at runtime. Its prompt is opinionated: patch existing skills before creating new ones, treat user frustration as a first-class signal, and never save "tool X is broken" — these harden into refusals the agent cites against itself for months.

turn endsreply already sent nudge counters 10 turns w/o memory ·10 iters w/o skill write tripped? background fork replays snapshot · whitelist:memory + skill tools ONLY MEMORY.mdwho you are skills/how to do it main conversation + prompt cache: never touched counters reset whenever the tools get used — the nudge only fires when the agent has NOT been saving same-model fork rides the warm prompt cache; cheap-model fork gets a digest instead
The meta layer runs after delivery, out-of-band, with a two-tool whitelist. "Periodic nudges" are counters, not injected text — the conversation never sees them.

7Recall & shrink

The context window and the brain shrink on different rules. The window: compression fires at 50% capacity, folds the middle into a summary — and here is the load-bearing trick — the folded turns are soft-archived, not deleted, so session search still finds them. Recall is keyword-only FTS5, zero LLM, ~20ms, with hand-tuned ranking (cron sessions demoted so their repetitive vocabulary can't cause "recall blindness"). The skill library gets the night shift (Hermes's curator — idle-triggered, weekly): stale skills are archived, never deleted, and pinned ones are untouchable.

context window first 3 turns · protected middle → summaryat 50% of window recent turns · protected soft-archive state.db (SQLite) every turn ever · 3 FTS5 indexes active=0 · compacted=1 still searchable ↓ session_searchFTS5 · no LLM model can pull anything back on demand — leaving the window ≠ leaving the brain micro-compaction (opt-in, off): pays the same bill in instalments but breaks the cache every turn
Two different lifetimes: the window shrinks aggressively, the store never forgets. Compaction moves turns from gold to verdigris — out of the paid context, into the free archive.
  • tools/session_search_tool.py out-of-band — discovery/scroll/browse; kanban and subagent sessions hidden, cron demoted.
  • hermes_state.py:7656 out-of-bandarchive_and_compact: one session id for life, history intact.
  • agent/curator.py out-of-band — the night shift: stale→archive, never delete; cron-referenced and pinned skills protected.
  • docs/micro-compaction.md in-context — the most honest trade-off doc in the repo: user messages are never compacted, because instructions cannot be reconstructed from the work that followed.
  • agent/title_generator.py out-of-band — two-stage titles; a model can never overwrite a user-typed name.

8The clock

Scheduled life has two modes. Normally the gateway ticks every 60 seconds under a file lock and runs due jobs — each in its own cron session (never spliced into your conversation, memory writes off, a 3-minute hard interrupt so a runaway loop can't monopolize the scheduler). For hosted agents that scale to zero, Chronos inverts the clock: the agent arms one external one-shot per job at its real next fire time, then sleeps entirely; the fire arrives as a short-lived signed token. A blueprint, meanwhile, is just a skill with a schedule in its frontmatter — no new object type.

mode 1 · always-on box tick60s due jobs cron session own transcript · no memory · 3-min hard stop deliver any platform mode 2 · scale-to-zero (Chronos) agentthen sleeps 💤 arm 1 one-shot NAS schedulerholds all creds fire: 60–120s JWT wake + verify202 first, run after re-arm no periodic wake — that would negate scale-to-zero
The clock matches the deployment: an always-on box polls; a serverless agent is woken exactly once per fire, and the scheduler's credentials never leave the trust service.
  • cron/scheduler.py out-of-band — the tick loop; failures summarized to one line so stack traces don't hit your chat.
  • cron/jobs.py:612 out-of-band — natural-language schedules ("every morning", 30m, cron exprs), anchored to your timezone.
  • plugins/cron_providers/chronos/ out-of-band — the scale-to-zero provider; falls back to the ticker if unavailable — cron never loses its trigger.
  • tools/blueprints.py out-of-band — blueprint = skill + schedule; rides the whole existing skills-hub pipeline for free.
  • gateway/scale_to_zero.py out-of-band — gateway hibernation on Fly; the reason Chronos exists.

9Day zero & staying alive

Install is a one-liner (shell, Docker, or Nix — pip is deliberately blocked because a wheel would ship without the bundled skills and assets). hermes update git-pulls with surgical restore and prints rollback instructions with the exact pre-pull SHA when it fails; hermes doctor runs security advisories first. And growth itself is governed: every new capability must climb the Footprint Ladder, where each rung costs more context than the last — the top rung, a new core tool, is paid on every API call and is the explicit last resort.

extend existing CLI + skill gated tool plugin MCP catalog new core tool context cost per API call rises → last resort: paid every call, every session expansive at the edges… skills & plugins: zero model-tool footprint — free until loaded
The extension model as economics: rungs on the left add capability without touching the window; only the top rung taxes every future API call. Three or more competing PRs in one category ⇒ design an interface and make them all plugins.
  • setup-hermes.sh out-of-band — installer; Termux gets a curated dependency set.
  • hermes_cli/update_cmd.py out-of-band — targeted fetch, pre-update backup, in-process module reload, rollback SHA on failure.
  • hermes_cli/doctor.py out-of-band — advisories first (compromised-package scan), then --fix repairs.
  • hermes_cli/plugins.py out-of-band — plugin discovery: hooks, tools, CLI commands, platforms; plugins may never patch core files.
  • hermes_cli/mcp_catalog.py out-of-band — curated MCPs: SHA-pinned, ≥2 weeks old at pin time, never auto-updated.

Roster

The load-bearing components, grouped by job. Long tails (77 bundled skills, 114 optional skills, 22 platform connectors, 33 model providers) are rolled up as directory rows — the atlas links the door, not every room.

Bodies — where you meet the agent

componentwhat it does
cli.pyin-contextThe interactive terminal client — 870 KB of it.
ui-tui/out-of-bandInk/Node terminal UI; TypeScript owns the screen, Python owns everything else.
tui_gateway/out-of-bandPython side of the TUI, JSON-RPC over stdio; resolves per-session toolsets.
gateway/run.pyout-of-bandThe messaging gateway process; caches ≤128 agents with memory-pressure eviction.
apps/desktop/out-of-bandElectron desktop app.
acp_adapter/out-of-bandACP server for VS Code, Zed, JetBrains.
mcp_serve.pyout-of-bandExposes Hermes conversations as MCP tools to other clients — the inverted direction.
hermes_cli/web_server.pyout-of-bandDashboard; its chat is the real TUI over a PTY WebSocket.

Agent core — the turn

componentwhat it does
run_agent.pyin-contextAIAgent: state, streaming, interrupts; the loop body moved out.
agent/conversation_loop.pyin-contextThe real turn loop: model → tools → repeat, compression, retries.
agent/prompt_builder.pyin-contextSystem-prompt assembly + context-file injection blocking + the honesty rail.
agent/turn_context.pyin-contextPer-turn state; hydrates nudge counters on resume.
agent/turn_finalizer.pyout-of-bandTeardown; fires micro-compaction and the background review.
agent/tool_executor.pyin-contextConcurrent/sequential dispatch; deterministic approval ordering.
agent/transports/out-of-bandProvider wire adapters (chat-completions, Anthropic, Bedrock, Codex).
agent/iteration_budget.pyout-of-band500-iteration cap with refunds and one grace call.
agent/context_engine.pyin-contextABC for swappable context managers; default is the built-in compressor.

Gateway & platforms

componentwhat it does
gateway/session.pyout-of-bandSession keys, multi-user isolation, hostile-metadata neutralization.
gateway/authz_mixin.pyout-of-bandDefault-deny authorization; two regression comments against fail-open.
gateway/pairing.pyout-of-bandDM pairing: hashed codes, lockout-before-lookup, operator-only approval.
gateway/platform_registry.pyout-of-bandPlugin platform registry; passive probe vs active installer split (#79812).
gateway/mirror.pyout-of-bandCross-session delivery mirroring with role rules that keep alternation legal.
gateway/relay/out-of-bandHosted-gateway relay: zero public inbound surface, fail-closed tenant routing.
gateway/profile_routing.pyout-of-bandMulti-profile message routing; byte-identical no-op when off.
plugins/platforms/out-of-band22 connectors: telegram, discord, slack, whatsapp, email, matrix, teams, irc…
gateway/platforms/out-of-bandNative adapters: Signal, WhatsApp Cloud, WeChat, QQ, BlueBubbles, webhooks, API server.

Memory & learning — the brain

componentwhat it does
tools/memory_tool.pyin-contextThe two-file brain; frozen snapshot, char caps, strict filing gate.
agent/memory_manager.pyout-of-bandProvider orchestration: off-thread sync, FIFO, bounded shutdown drain.
plugins/memory/out-of-band8 swappable providers (honcho, hindsight, openviking, holographic, mem0…); tree closed to new ones.
agent/background_review.pyout-of-bandThe learning-loop fork; memory+skill whitelist, negative-capture blocklist.
agent/curator.pyout-of-bandThe night shift for skills: archive-only, pinned exempt, cron-referenced protected.
tools/skills_tool.pyin-contextRead side: progressive disclosure — index → SKILL.md → linked files.
tools/skill_manager_tool.pyout-of-bandWrite side with provenance; agent skills quarantined from bundled ones.
tools/session_search_tool.pyout-of-bandCross-session recall: FTS5, zero LLM, rank surgery against recall blindness.
hermes_state.pyout-of-bandThe SQLite session DB: soft-archive compaction, provenance-ordered titles.
skills/in-context77 bundled skills in 15 categories (github, creative, productivity, research…).
optional-skills/out-of-band114 more in 20 categories, installed on demand from the hub.

Execution & guards

componentwhat it does
toolsets.pyin-context59 toolsets over ~84 tools; webhook toolset is 4 read-only tools by design.
model_tools.pyin-contextTool resolution: disabled always subtracts last; schemas rebuilt against reality.
tools/registry.pyout-of-bandcheck_fn-gated registration with TTL cache and last-good grace.
tools/approval.pyin-contextThe guard chain: hard rails before yolo, ~90 heuristic patterns, LLM guard.
tools/threat_patterns.pyout-of-bandOne pattern library, three scopes; anchors on attack vocabulary, not bossy English.
agent/tool_dispatch_helpers.pyin-contextUntrusted-result delimiters — the architectural injection defense.
agent/redact.pyout-of-bandSecret masking on terminal output before the model sees it.
agent/secret_sources/out-of-bandBitwarden / 1Password backends over one shared 0600+TTL cache substrate.
tools/delegate_tool.pyout-of-bandSubagents: fresh context, blocked-tool list with reasons, summary-only return.
tools/code_execution_tool.pyout-of-bandScript tool-calling over RPC; stdout-only return, iterations refunded.
tools/environments/out-of-band7 backends: local, docker, ssh, singularity, modal, daytona, vercel sandbox.
tools/budget_config.pyin-contextPer-result and per-turn character budgets, scaled to the model's window.

Clock & operations

componentwhat it does
cron/scheduler.pyout-of-band60s tick under a file lock; isolated cron sessions, one-line failure summaries.
cron/jobs.pyout-of-bandJob store; natural-language schedules in the user's timezone.
plugins/cron_providers/out-of-bandChronos: NAS-mediated one-shot fires for scale-to-zero deployments.
tools/blueprints.pyout-of-bandBlueprint = skill + schedule; no new object type, rides the skills pipeline.
hermes_cli/update_cmd.pyout-of-bandhermes update: backup, surgical restore, rollback SHA on failure.
hermes_cli/doctor.pyout-of-bandDiagnostics; security advisories run first, --fix repairs.
plugins/model-providers/out-of-band33 declarative provider profiles; user plugins override bundled by name.
optional-mcps/out-of-band6 curated MCPs (blender, figma, linear, n8n…), SHA-pinned, never auto-updated.
batch_runner.pyout-of-bandResearch mode: batch trajectory generation for training tool-calling models.
AGENTS.mdout-of-bandThe 77 KB constitution: cache rules, footprint ladder, testing bans, closure policies.
SECURITY.mdout-of-bandThe threat model that names its own heuristics as heuristics.
← Accession