Hermes
- ID:
hermes - Store:
~/.hermes/state.db(0.17+) or~/.hermes/profiles/<profile>/state.db(older builds, one store per profile) - Home:
HERMES_HOME, Hermes's own variable, is followed — profiles, plugins andconfig.yamlare read and written under it.DEJA_HERMES_HOMEoverrides it. - Read overrides:
DEJA_HERMES_PROFILES_ROOTfor the profiles directory,DEJA_HERMES_DBto pin a single store - Postgres: with
sessiondb.provider: postgresqlHermes stops writingstate.db; setDEJA_HERMES_PG_DSNand deja reads the same columns from themessagestable throughpsql(#1018) - Format: SQLite relational store
A flat messages table, grouped by session_id: role, content, and timestamp
as REAL epoch seconds. An assistant row that calls tools has no content and an
OpenAI-style tool_calls array instead; the result lands on a tool row under the
same tool_call_id. Calls to terminal become commands: a non-zero exit_code from
the result rides on the command. -1, which Hermes returns for a command it never
ran (denied, blocked, waiting on approval), drops the command record; any other
negative code is a process killed by a signal after it started, so the command stays. read_file,
write_file and patch name the files, and patch and write_file give the edit and
written sides — patch in its V4A mode as Hermes' own parser reads it, Move File
included, with the lines after a move or delete belonging to no file. A tool row is
kept as tool output by its output, content, diff, matches_text or error, or,
when it has none of those keys, by every string in it (search_files in files mode,
web_search, delegate_task); keys starting with _ and a bare byte count are not
kept. Rows rewound away (active = 0, compacted = 0, or active = 0 on a store
without compacted) are skipped. Rows are read in insertion order, as Hermes reads them, on SQLite and Postgres alike.
In-place compaction archives the turns it summarises and writes the kept head, a
summary and the kept tail as one batch of live rows, in one transaction at the
summary's time or under each row's original timestamp. Head rows that repeat the start
of what was archived and tail rows that repeat its end, with such a timestamp, are that
batch's copies and are not read twice (#4296); every summary anchors one, so a second
compaction's archive of the first batch is read once too. The same request or run
later counts again, and so does a tool result that is neither the archived one nor a
stub. The summary ([CONTEXT COMPACTION … or the older [CONTEXT SUMMARY]:) is kept
under the summary role; when Hermes merged it into the first tail message, the text
after its end marker keeps that message's role. The placeholder compaction leaves for an
image it stripped is not text. The compressor's stubs are dropped. Multimodal content, stored as
\x00json: and a list of parts, keeps its text parts and not the image (#4242). The
Postgres path still reads prose only. A sessions table beside it carries id, cwd,
git_repo_root and title; the cwd is where the work happened and is what names
the project, the same way a Cline or Roo workspace does. A store without that table,
or a session whose row has no cwd, falls back to the profile name. The title is left
to the index rather than taken from the first row.
- MCP:
mcp_serversin~/.hermes/config.yaml;deja install hermes-autoalso drops a plugin (~/.hermes/plugins/deja, added toplugins.enabled) whosepre_llm_callhook injects recall and registers/deja, and whosetransform_tool_resulthook appends what was run after the same error before to aterminalresult that did not exit 0, and a memory provider (deja-memory) thathermes memory setuplists next to mem0 and supermemory — the same recall in thememory.providerslot, withdeja_recall,deja_fixanddeja_blameas its tools. The provider is written against the interface Hermes has:RecallStatusarrived afterMemoryProvider, so it is imported behind a guard and the status line is skipped where the class is missing — checked against Hermes 0.17.0, which has none. The hook stands aside for the provider only after loading it, so a provider that cannot import leaves the hook doing the recall rather than nobody. - Skill:
~/.hermes/skills/deja-history/SKILL.md, top-level rather than inside the plugin: a plugin-bundled skill is opt-in in Hermes and never reaches the system prompt. - Resume:
hermes --resume <id>; Hermes takes the same session id deja indexes, so it reopens that conversation rather than the most recent one. A session from a profile's store gets-p <profile>, since resume looks only in the active profile, and a root-store session gets-p defaultwhen another profile is active or deja runs under a profile'sHERMES_HOME. A profile directory Hermes does not take by name (a reserved one likedefaultortmp, or one outside its[a-z0-9_-]pattern) and a session deleted withhermes sessions deleteare refused with a pointer todeja show. - Handoff: paste.
Requested in #355.
Last verified: 2026-07-28
deja reads this format and thirty-seven others, and turns what it finds into memory your agents can search. See the harness matrix for what is wired where, or install it and search your own history.
Found this useful? Star deja-vu on GitHub.