Hermes Journal Writer
Journal Writer — reads research-collector data from the swamp catalog and writes org-mode journal entries to ~/org/journal/. Commits and pushes to the org repo so entries become part of your living knowledge store.
Methods
- write_daily_entry — Writes a daily research summary to ~/org/journal/YYYY-MM-DD-dow.org with property drawer, source links, and summaries from HN, Lobste.rs, SRE Weekly, IFIN, and RedMonk.
Render The AI Daily Brief editions in daily org entries: new aiDailyBrief source (on by default) adds an edition section with date, title, tags, thesis, URL, and written takeaways. Upgrade backfills aiDailyBrief onto existing instances' sources list.
Global Arguments
| Argument | Type | Description |
|---|---|---|
| orgDir | string | Root directory of the org repo (supports ~ expansion) |
| jrnlSubdir | string | Subdirectory under orgDir for journal entries |
| swampBin | string | Path to the swamp binary (must be on PATH or specify full path) |
| repoDir | string | Path to the swamp repo directory |
| gitUserName | string | Git commit user name |
| gitUserEmail | string | Git commit user email |
| sources | array | Which sources to include in the journal entry. Omit a source name to disable it. |
Resources
2026.07.18.1
Added: An upgrades array entry (no-op) to hermes_jrnl_writer.ts for proper typeVersion tracking on existing instances. No schema or behavior changes.
2026.07.09.1
Fixed: write_daily_entry failed argument validation under swamp. Its method
arguments schema was z.object({}).strict(), and .strict() rejects the extra
keys swamp injects into a method call — so every invocation errored before the
method body ran. The schema is now z.object({}) (no .strict()), accepting the
call as swamp makes it.
No behavioral change to the journal output or git handling: every safeguard from
2026.07.08.1 (single-colon FILETAGS, skipped-no-data, honest git status codes,
single-file commit, stat rethrow, timeout cleanup) is unchanged.
2026.07.08.1
Changed: One org file per day instead of a monthly rollup.
- Journal entries are now written to
YYYY-MM-DD-dow.org(e.g.2026-07-08-wed.org), each a standalone org document with#+TITLE,#+DATE, and#+FILETAGSheaders. Writing is idempotent — an existing file for the day is left untouched. - Section headings are now level-1 (
* Hacker News) since the day's entry is the whole document, rather than the***/****levels that assumed nesting inside a monthly file. #+FILETAGSare now joined with single colons (:a:b:); the previous join emitted a doubled colon (:a::b:) that org parses as an empty tag. Tags that sanitize to an empty string are dropped rather than emitted.- A run with no research data now writes and commits nothing (status
skipped-no-data) instead of committing a "No research data" placeholder. The placeholder would trip the idempotency guard and permanently block a later run that day from writing the real entry once the collector had run.
Added:
sourcesglobal arg — an array drawn from["hn", "lobsters", "sre", "ifin", "redmonk", "arxiv"]. Defaults to all sources; remove a name to disable that source. An unset/empty value is treated as "all sources".- arXiv entries are now rendered as an
* arXivsection (previously collected but never written out).
Fixed:
- Git failures are no longer reported as success. The recorded status now
reflects what actually reached the remote:
written(committed and pushed),committed-not-pushed(push failed),written-not-committed(commit failed), orwritten-nothing-to-commit(the file already matched the last commit, so no push was attempted). A failedgit status(e.g. a heldindex.lock) is treated as an error rather than "nothing to commit". - The commit now stages and commits only the day's file (
git add -- <file>) rather than the whole journal subdirectory, so an unrelated in-progress edit is never swept into the bot commit. - The idempotency guard now rethrows non-
NotFoundstaterrors (permission denied, I/O) instead of swallowing them and failing later without context. runCommandclears its timeout timer in afinallyblock, so the timer no longer leaks if the subprocess call rejects.- Reads the
researchdata spec first (the current@webframp/research-collectoroutput), falling back to the legacybriefspec for older instances.
2026.07.08.1
Changed: One org file per day instead of a monthly rollup.
- Journal entries are now written to
YYYY-MM-DD-dow.org(e.g.2026-07-08-wed.org), each a standalone org document with#+TITLE,#+DATE, and#+FILETAGSheaders. Writing is idempotent — an existing file for the day is left untouched. - Section headings are now level-1 (
* Hacker News) since the day's entry is the whole document, rather than the***/****levels that assumed nesting inside a monthly file. #+FILETAGSare now joined with single colons (:a:b:); the previous join emitted a doubled colon (:a::b:) that org parses as an empty tag. Tags that sanitize to an empty string are dropped rather than emitted.
Added:
sourcesglobal arg — an array drawn from["hn", "lobsters", "sre", "ifin", "redmonk", "arxiv"]. Defaults to all sources; remove a name to disable that source. An unset/empty value is treated as "all sources".- arXiv entries are now rendered as an
* arXivsection (previously collected but never written out).
Fixed:
- Git failures are no longer reported as success. A failed
git pushnow records the entry ascommitted-not-pushed(and a failed commit aswritten-not-committed) instead of logging "Pushed to remote" and recordingwritten. The recorded status reflects what actually reached the remote. - The commit now stages and commits only the day's file (
git add -- <file>) rather than the whole journal subdirectory, so an unrelated in-progress edit is never swept into the bot commit. - The idempotency guard now rethrows non-
NotFoundstaterrors (permission denied, I/O) instead of swallowing them and failing later without context. runCommandclears its timeout timer in afinallyblock, so the timer no longer leaks if the subprocess call rejects.- Reads the
researchdata spec first (the current@webframp/research-collectoroutput), falling back to the legacybriefspec for older instances.
- Has README or module doc2/2earned
- README has a code example1/1earned
- README is substantive1/1earned
- Most symbols documented1/1earned
- No slow types (deprecated)1/1earned
- Dependencies pass trust audit2/2earned
- Has description1/1earned
- Platform support declared (or universal)2/2earned
- License declared1/1earned
- Verified public repository2/2earned