34 KiB
Phase 8: Cron Reporting - Research
Researched: 2026-06-15 Domain: Hermes cron scheduling, session lifecycle management, Telegram delivery, Jira integration via cron Confidence: HIGH
Summary
Phase 8 implements daily operational reporting and weekly stale session lifecycle management using Hermes' built-in cron and session management capabilities. Three cron jobs are needed: a daily report (skill-backed), a weekly stale summary (skill-backed), and a weekly archive (no_agent). All use hermes cron create with appropriate flags.
Critical finding: The CONTEXT.md assumptions about hermes sessions export flags are incorrect — --older-than and --output do not exist on the export command. The export takes a positional output path and supports only --source and --session-id filters. The archive script must compensate by exporting all sessions and relying on the separate prune --older-than 30 step to remove old ones.
Primary recommendation: Two skill-backed cron jobs (daily report 09:00 SGT, weekly summary Sunday 20:00 SGT) plus one no_agent script cron (archive Sunday 20:05 SGT). The Jira-session mapping is not a direct DB field — the skill-backed cron agents use hindsight_recall or session_search to discover ticket keys from session summaries stored by Phase 7's session skill.
<user_constraints>
User Constraints (from CONTEXT.md)
Locked Decisions
- D-01: Daily report runs at 09:00 SGT (UTC+8) — Hermes cron job using
hermes cron create - D-02: Weekly stale session summary runs Sunday 20:00 SGT (UTC+8) — separate cron job
- D-03: Weekly stale session archive runs Sunday 20:00 SGT (UTC+8) — same cron job as summary (archive after summary)
- D-04: Daily report updates all Jira tickets linked to active sessions with last activity and progress
- D-05: Do NOT update Jira ticket statuses — only add comments with session progress/state
- D-06: Daily report delivered via Telegram to user's DM channel
- D-07: Report includes: list of active sessions, last activity timestamp, Jira ticket keys updated
- D-08: Weekly report summarizes all inactive sessions (>30d since last activity)
- D-09: Delivered via Telegram to user's DM channel
- D-10: No auto-comments on stale tickets — only reported in the summary
- D-11: Use native Hermes commands for archive (export + prune) — no custom scripts for core logic
- D-12: Archive location:
~/.hermes/archive/sessions/ - D-13: Run weekly Sunday 20:00 SGT, after the stale summary report
- D-14: Active sessions with linked Jira tickets get daily progress comments
- D-15: Stale sessions with Jira tickets are mentioned in the weekly summary only
- D-16: Ticket status transitions only happen when user explicitly asks
- D-17: Both cron jobs use Hermes skill-backed cron
- D-18: The daily report skill references the existing session skill and ngn-jira skill
- D-19: The stale archive step uses
no_agent: truemode
the agent's Discretion
- Report formatting: Telegram message structure (sections, bullet points) — planner can design based on Telegram's 4096-char limit
- Cron job naming: Standard naming convention for the two cron jobs
- Dry-run phase: First archive run should be manual (export then review JSONL before enabling prune)
Deferred Ideas (OUT OF SCOPE)
- Auto-close tickets for archived sessions — user wants manual control
- Teams gateway delivery — only Telegram for now
- Custom archive dashboard — JSONL files are searchable via grep/FTS5 </user_constraints>
<phase_requirements>
Phase Requirements
| ID | Description | Research Support |
|---|---|---|
| CRON-01 | Daily session summary report delivered via Telegram at 09:00 | hermes cron create --deliver telegram --skill session --skill jira-query "0 9 * * *" — verified working. Daily report prompt guides agent to list active sessions, query Jira, compose Telegram message. |
| CRON-02 | Stale session auto-archive (30d inactivity) — export to JSON, delete from live DB | hermes sessions export <path> + hermes sessions prune --older-than 30 --yes. Export lacks --older-than filter, so archive script exports all sessions. Prune correctly filters by age. Verified working. |
| CRON-03 | Daily report includes Jira ticket status via ngn-jira skill | ngn-jira script available at ~/.hermes/scripts/ngn-jira. Jira-session mapping lives in hindsight memory (session summaries) and session message content, not as a direct DB field. |
| </phase_requirements> |
Architectural Responsibility Map
| Capability | Primary Tier | Secondary Tier | Rationale |
|---|---|---|---|
| Daily report scheduling | Cron scheduler (Hermes gateway) | — | hermes cron create registers the job; Hermes gateway process fires it on schedule |
| Active session discovery | Cron agent (LLM) | Session DB (SQLite) | Skill-backed cron agent runs hermes sessions list or hermes sessions export - to enumerate sessions and determine active/stale via last_active timestamps |
| Jira comment posting | Cron agent (LLM) | ngn-jira script |
Agent crafts ngn-jira POST '/rest/api/3/issue/<KEY>/comment' for each active session with a Jira link |
| Telegram message delivery | Hermes cron delivery system | — | --deliver telegram sends cron agent's response to TELEGRAM_HOME_CHANNEL (474440517) |
| Stale session archive | no_agent script (bash) | Hermes CLI | --no-agent mode runs ~/.hermes/scripts/archive-stale-sessions.sh which calls hermes sessions export + hermes sessions prune directly |
| Jira-session mapping lookup | Hindsight memory / session_search | Session message content | No direct jira_key field in session DB; mapping is discovered through hindsight recall of session summaries or searching session messages |
Standard Stack
Core
| Library/Tool | Version | Purpose | Why Standard |
|---|---|---|---|
hermes cron create |
v0.16.0 | Register scheduled cron jobs | Built-in — no external scheduler needed |
hermes sessions export |
v0.16.0 | Export sessions to JSONL backup | Native Hermes command, writes full session data (messages included) |
hermes sessions prune |
v0.16.0 | Delete old sessions from live DB | Native Hermes command with --older-than and --yes flags |
hermes sessions list |
v0.16.0 | List recent sessions with last active times | Native Hermes command, human-readable table output |
ngn-jira script |
— | Jira Cloud API wrapper (GET/POST/PUT/DELETE) | Already exists in ~/.hermes/scripts/, used by Phase 7 session skill |
Supporting
| Library/Tool | Version | Purpose | When to Use |
|---|---|---|---|
session skill (Phase 7) |
v1.0.0 | Session lifecycle definitions and hindsight session summaries | Daily and weekly cron jobs load this to understand session structure and Jira mapping |
jira-query skill (Phase 4) |
v1.0.0 | Jira API query patterns | Daily report cron job loads this for Jira comment operations |
bash (no_agent script) |
system | Deterministic archive operations without LLM cost | Archive step only — pure CLI, no LLM involvement |
jq (optional) |
system | Filter JSONL for precise archive content | Optional — only needed if archive should contain only stale sessions (avoids dependency) |
date command |
system | Date-stamped archive filenames | $(date +%Y%m%d) for sessions-20260615.jsonl naming |
Alternatives Considered
| Instead of | Could Use | Tradeoff |
|---|---|---|
| Skill-backed cron | --script + --no-agent for daily report |
Need LLM for composing natural-language reports and determining active vs stale from context |
| Separate cron jobs | Single cron with complex script | Cleaner separation of concerns — daily vs weekly have different scopes |
| Custom Jira field for session-ID | Hindsight + session_search lookup | Adding custom Jira fields requires admin access and changes existing workflow |
Installation:
# No new packages needed — all tools are native Hermes CLI or existing scripts
# Create archive directory:
mkdir -p ~/.hermes/archive/sessions
Version verification:
hermes --version
# Hermes Agent v0.16.0 (2026.6.5) · upstream 78c11d99
# Verify ngn-jira script exists:
file ~/.hermes/scripts/ngn-jira
# Bourne-Again shell script, ASCII text
# Verify hermes sessions commands available:
hermes sessions --help
hermes cron --help
Package Legitimacy Audit
No external packages are installed in this phase. All dependencies are native Hermes CLI commands and existing scripts.
| Package | Registry | Age | Downloads | Source Repo | Verdict | Disposition |
|---|---|---|---|---|---|---|
| (none) | — | — | — | — | — | No packages to audit |
Packages removed due to [SLOP] verdict: none Packages flagged as suspicious [SUS]: none
Architecture Patterns
System Architecture Diagram
┌──────────────────────────────────────────────────────────────────┐
│ HERMES GATEWAY PROCESS │
│ (cron scheduler — checks every minute, fires due jobs) │
└──────┬────────────────────────────────┬───────────────────────────┘
│ │
▼ ▼
┌────────────────┐ ┌──────────────────────────┐
│ DAILY REPORT │ │ WEEKLY SUNDAY 20:00 SGT │
│ 09:00 SGT │ │ │
│ skill-backed │ ├─────────────────────┬────┤
│ with session + │ │ Weekly Stale │ │
│ jira-query │ │ Summary │ │
│ skills │ │ (skill-backed) │ │
└────────┬───────┘ └──────────┬────────────┘ │
│ │ │
▼ ▼ ▼
┌─────────────────┐ ┌────────────────┐ ┌─────────────────┐
│ Agent loads │ │ Agent queries │ │ no_agent script │
│ skills, runs: │ │ sessions list, │ │ runs: │
│ │ │ finds stale >30d│ │ │
│ 1. hermes │ │ identifies Jira │ │ 1. hermes │
│ sessions list │ │ tickets (via │ │ sessions │
│ → find active │ │ hindsight) │ │ export │
│ sessions │ │ composes stale │ │ → archive │
│ │ │ summary report │ │ │
│ 2. hindsight │ │ sends Telegram │ │ 2. hermes │
│ _recall → │ │ DM │ │ sessions │
│ find Jira keys│ └────────────────┘ │ prune │
│ for each │ │ --older-than │
│ active session│ │ 30 --yes │
│ │ └────────┬────────┘
│ 3. ngn-jira POST │ │
│ → add progress │ ▼
│ comment on │ ┌─────────────────┐
│ each Jira │ │ ~/.hermes/archive│
│ ticket │ │ /sessions/ │
│ │ │ sessions- │
│ 4. sends │ │ 20260615.jsonl │
│ Telegram DM │ └─────────────────┘
│ summary │
└─────────────────┘
TELEGRAM_HOME_CHANNEL (474440517)
▲ ▲
│ │
Daily Report Weekly Summary
│ │
┌─────┴──────────────┴──────┐
│ USER's TELEGRAM DM │
└────────────────────────────┘
Recommended Project Structure
No new project files needed — all configuration is in ~/.hermes/:
~/.hermes/
├── config.yaml # Already configured: TELEGRAM_HOME_CHANNEL, cron section
├── scripts/
│ ├── ngn-jira # Existing — Jira Cloud API wrapper
│ ├── ngn-confluence # Existing
│ ├── ngn-bitbucket # Existing
│ ├── session-init.sh # Existing
│ └── archive-stale-sessions.sh # NEW — no_agent archive script
├── cron/
│ └── output/ # Cron output logs (auto-managed by Hermes)
└── archive/
└── sessions/ # NEW — stale session JSONL archives
└── sessions-20260615.jsonl # Named by date
Pattern 1: Skill-Backed Cron Job Registration
What: Register a cron job that loads one or more skills and instructs an LLM agent to perform a task on a schedule.
When to use: Any recurring task that requires natural language composition, decision-making, or tool orchestration.
Example:
# Register daily report (skill-backed)
hermes cron create \
--name "ngn-daily-report" \
--deliver telegram \
--skill session \
--skill jira-query \
"0 9 * * *" \
"Daily operational report: list all active sessions with their last activity timestamps using hermes sessions list, for each active session find its linked Jira ticket via hindsight_recall or message search, then add a progress comment via ngn-jira POST /rest/api/3/issue/<KEY>/comment, and finally compose a Telegram summary of all updated tickets and active sessions."
# Register weekly stale summary (skill-backed)
hermes cron create \
--name "ngn-weekly-stale-summary" \
--deliver telegram \
--skill session \
"0 20 * * 0" \
"Weekly stale session summary: run hermes sessions list to find all sessions, identify sessions where last activity is more than 30 days ago (stale), for each stale session find its linked Jira ticket via hindsight_recall, compose a summary report with session title, last activity date, and linked Jira ticket. Do NOT add Jira comments — only report in the summary. Send via Telegram."
Verification:
# List registered cron jobs
hermes cron list
# Test-run a cron job
hermes cron run ngn-daily-report
# Check cron scheduler status
hermes cron status
Pattern 2: no_agent Deterministic Cron Script
What: Register a cron job that runs a shell script without LLM involvement, delivering its stdout verbatim to the target.
When to use: Deterministic CLI operations that don't need AI reasoning (backup, cleanup, export).
Example script (~/.hermes/scripts/archive-stale-sessions.sh):
#!/bin/bash
# Archive stale sessions (inactive >30 days) and prune from live DB
set -euo pipefail
ARCHIVE_DIR="$HOME/.hermes/archive/sessions"
mkdir -p "$ARCHIVE_DIR"
OUTPUT_FILE="$ARCHIVE_DIR/sessions-$(date +%Y%m%d).jsonl"
echo "=== Stale Session Archive: $(date) ==="
echo ""
echo "1. Exporting all sessions to $OUTPUT_FILE ..."
hermes sessions export "$OUTPUT_FILE"
export_exit=$?
echo " Export exit code: $export_exit"
echo " File size: $(wc -c < "$OUTPUT_FILE") bytes"
echo ""
echo "2. Pruning sessions older than 30 days from live DB ..."
hermes sessions prune --older-than 30 --yes
prune_exit=$?
echo " Prune exit code: $prune_exit"
echo ""
echo "3. Session store stats after archive:"
hermes sessions stats
echo ""
if [ $export_exit -eq 0 ] && [ $prune_exit -eq 0 ]; then
echo "Archive completed successfully."
else
echo "Archive completed with warnings (see exit codes above)."
fi
Registration:
# Register weekly archive (no_agent, 5 min after stale summary to avoid race)
hermes cron create \
--name "ngn-weekly-archive" \
--deliver telegram \
--script archive-stale-sessions.sh \
--no-agent \
"5 20 * * 0"
Anti-Patterns to Avoid
- Race condition on same schedule: If weekly summary and archive run at exactly the same time, the prune might remove sessions while the summary is still being composed. Offset by at least 5 minutes (e.g., 20:00 summary, 20:05 archive).
- Custom cron daemon: Hermes already has a full cron implementation — no need for system cron, launchd, or external schedulers.
- Storing Jira key as session metadata: The session DB has no
jira_keyfield. Attempting to add one would require modifying Hermes internals. Use hindsight memory for the mapping (as designed by Phase 7).
Don't Hand-Roll
| Problem | Don't Build | Use Instead | Why |
|---|---|---|---|
| Scheduling recurring tasks | Custom cron/launchd/service | hermes cron create |
Hermes gateway manages scheduling, delivery, retries, and logging natively |
| Session backup/export | Custom SQLite query tool | hermes sessions export |
Native JSONL export includes complete session data (messages, tokens, costs) |
| Session cleanup | Custom deletion script | hermes sessions prune |
Handles DB vacuuming and FTS index maintenance after deletion |
| Telegram message delivery | Custom Telegram bot | --deliver telegram |
Uses existing TELEGRAM_HOME_CHANNEL config and channel_directory |
| Jira API integration | Custom HTTP calls | ngn-jira script |
Existing script handles auth, base URL, error handling |
Key insight: Every tool needed for this phase already exists in the Hermes ecosystem. The phase is about composing them through cron job registration, not building new components. The only new file is the archive-stale-sessions.sh script.
Common Pitfalls
Pitfall 1: Export lacks --older-than filter
What goes wrong: CONTEXT.md specifies hermes sessions export --older-than 30d --output <path> but this flag does not exist.
Why it happens: The export command only supports --source and --session-id filters.
How to avoid: The no_agent archive script exports ALL sessions to the archive file, then the separate hermes sessions prune --older-than 30 --yes step removes only old ones from the live DB. This is safe — the archive is a snapshot and extra data in it is harmless.
Warning signs: hermes: error: unrecognized arguments: --older-than
Pitfall 2: Prune uses --yes not --confirm
What goes wrong: CONTEXT.md specifies hermes sessions prune --older-than 30d --confirm but the correct flag is --yes (or -y).
How to avoid: Use hermes sessions prune --older-than 30 --yes in the no_agent script. Without --yes, the command prompts for confirmation and blocks in no_agent mode.
Warning signs: Cron job hangs waiting for confirmation input.
Pitfall 3: hermes sessions list does NOT support --json
What goes wrong: The agent expects JSON output to parse session data programmatically.
How to avoid: For the skill-backed cron, the agent runs hermes sessions list and parses the human-readable table. Alternatively, use hermes sessions export - which outputs JSONL and can be parsed. The export includes all session metadata including last_active, source, title, message_count.
Warning signs: hermes: error: unrecognized arguments: --json
Pitfall 4: Jira-session mapping not in session DB
What goes wrong: The cron agent cannot find which Jira tickets belong to which sessions by querying the session DB.
Why it happens: Hermes session DB has no jira_key field. The mapping is recorded only in hindsight memory (session summaries saved by Phase 7's session skill) and in session message content.
How to avoid: The skill-backed cron agents should use hindsight_recall with query "session summary" to find Jira ticket keys, or use session_search tool to search session transcripts for ticket key patterns like PLATFORM-123.
Warning signs: Empty Jira update section in daily report.
Pitfall 5: Cron schedule interpretation (UTC vs local)
What goes wrong: Cron expression 0 9 * * * might be interpreted as UTC if the system timezone is not configured.
Why it happens: Hermes cron uses system timezone by default. With timezone: '' in config, it falls back to system default.
How to avoid: System already in SGT (UTC+8, confirmed via date +%Z → +08). The created test cron showed "Next run: 2026-06-16T09:00:00+08:00" confirming correct timezone handling. No TZ configuration needed.
Warning signs: Cron fires at wrong hour (e.g., 01:00 UTC instead of 09:00 SGT).
Pitfall 6: Cron job naming — must use unique name
What goes wrong: Hermes cron jobs are identified by name or ID. Using duplicate names may cause confusion.
How to avoid: Use descriptive unique names: ngn-daily-report, ngn-weekly-stale-summary, ngn-weekly-archive.
Warning signs: hermes cron list shows unexpected jobs.
Code Examples
Command 1: Create the daily report cron job
# Daily at 09:00 SGT — report on active sessions, update Jira tickets
hermes cron create \
--name "ngn-daily-report" \
--deliver telegram \
--skill session \
--skill jira-query \
"0 9 * * *" \
"Daily operational report: run hermes sessions list to find all active sessions (updated today or yesterday), for each active session search for its linked Jira ticket key using hindsight_recall with query 'session summary jira' or message search, then add a progress comment to each Jira ticket via ngn-jira POST /rest/api/3/issue/<KEY>/comment with the last activity timestamp and session summary, and finally compose a Telegram summary listing: active sessions with last activity, Jira ticket keys updated, and session titles."
Verified: hermes cron create --deliver telegram successfully creates jobs with correct timezone handling. [VERIFIED: Hermes CLI v0.16.0]
Command 2: Create the weekly stale summary cron job
# Sunday 20:00 SGT — stale session summary (no Jira comments)
hermes cron create \
--name "ngn-weekly-stale-summary" \
--deliver telegram \
--skill session \
"0 20 * * 0" \
"Weekly stale session summary: run hermes sessions list to find all sessions where last activity is more than 30 days ago. For each stale session, find the linked Jira ticket key via hindsight_recall if available. Compose a Telegram summary listing: session title, last activity date, linked Jira ticket. Do NOT add comments to Jira tickets — only report in the summary."
Verified: Cron schedule 0 20 * * 0 = Sunday at 20:00. [VERIFIED: conventional cron expression]
Command 3: Create the weekly archive cron job (no_agent)
# Create archive directory first
mkdir -p ~/.hermes/archive/sessions
# Register no_agent archive (5 min after summary to avoid race condition)
hermes cron create \
--name "ngn-weekly-archive" \
--deliver telegram \
--script archive-stale-sessions.sh \
--no-agent \
"5 20 * * 0"
Verified: --no-agent flag skips LLM entirely. Script must be under ~/.hermes/scripts/. Stdout delivered verbatim. [VERIFIED: Hermes CLI v0.16.0]
Command 4: Create the archive script
File: ~/.hermes/scripts/archive-stale-sessions.sh
#!/bin/bash
# Archive stale sessions (inactive >30 days) and prune from live DB
# This script runs weekly via hermes cron with --no-agent
# Stdout is delivered to Telegram via --deliver telegram
set -euo pipefail
ARCHIVE_DIR="$HOME/.hermes/archive/sessions"
mkdir -p "$ARCHIVE_DIR"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
OUTPUT_FILE="$ARCHIVE_DIR/sessions-${TIMESTAMP}.jsonl"
echo "=== Stale Session Archive ==="
echo "Started: $(date)"
echo ""
echo "[1/3] Exporting session store..."
hermes sessions export "$OUTPUT_FILE"
echo " -> $(wc -l < "$OUTPUT_FILE") sessions exported"
echo " -> Size: $(du -h "$OUTPUT_FILE" | cut -f1)"
echo ""
echo "[2/3] Pruning sessions older than 30 days..."
hermes sessions prune --older-than 30 --yes
echo " Done."
echo ""
echo "[3/3] Post-archive stats:"
hermes sessions stats
echo ""
echo "✓ Archive complete."
Verified: --older-than 30 takes integer days (not 30d), --yes skips interactive confirmation. [VERIFIED: Hermes CLI v0.16.0]
Command 5: List, test-run, and manage cron jobs
# List all cron jobs
hermes cron list
# Test-run a specific job (fires immediately)
hermes cron run ngn-daily-report
# Check if gateway/cron scheduler is running
hermes cron status
# → "Gateway is running — cron jobs will fire automatically"
# Remove a cron job (if needed)
hermes cron remove ngn-daily-report
# Edit an existing cron job (add/remove skills, change schedule)
hermes cron edit ngn-daily-report --add-skill jira-query
hermes cron edit ngn-daily-report --schedule "30 9 * * *"
Verified: All commands tested against Hermes CLI v0.16.0. [VERIFIED: Hermes CLI v0.16.0]
Command 6: Session management operations
# List all sessions
hermes sessions list
# Export all sessions to stdout (JSONL format)
hermes sessions export -
# Export to file
hermes sessions export /tmp/my-sessions.jsonl
# Show session store statistics
hermes sessions stats
# Filter sessions by source
hermes sessions list --source telegram
hermes sessions export telegram_sessions.jsonl --source telegram
# Prune old sessions (with confirmation prompt)
hermes sessions prune --older-than 30
# Without confirmation (for no_agent scripts):
hermes sessions prune --older-than 30 --yes
Verified: All commands tested. Export uses positional output arg, not --output. List does not support --json. Prune uses --yes not --confirm. [VERIFIED: Hermes CLI v0.16.0]
Command 7: Post-archive verification (dry-run procedure)
# Step 1: Manual export (dry-run — inspect before enabling prune)
hermes sessions export ~/.hermes/archive/sessions/sessions-$(date +%Y%m%d)-dryrun.jsonl
# Step 2: Review the exported JSONL
wc -l ~/.hermes/archive/sessions/sessions-*-dryrun.jsonl
# Check for sensitive data, verify format
# Step 3: Check which sessions would be pruned (no --dry-run flag on prune)
# Use export + filter to preview:
hermes sessions export - | python3 -c "
import sys, json, time
now = time.time()
for line in sys.stdin:
if line.strip():
s = json.loads(line)
age_days = (now - s['last_active']) / 86400
if age_days > 30:
print(f'WOULD PRUNE: {s[\"id\"]} — last active {age_days:.0f}d ago')
"
# Step 4: Only after review, enable prune in the cron script
State of the Art
| Old Approach | Current Approach | When Changed | Impact |
|---|---|---|---|
| Manual session management | Automated cron-driven lifecycle | Phase 8 | Sessions auto-archived after 30d inactivity, no manual cleanup needed |
| No reporting | Daily Telegram summaries with Jira progress | Phase 8 | Regular operational visibility without user having to ask |
| Jira tickets created but not tracked | Daily progress comments on linked tickets | Phase 8 | Jira tickets reflect real session activity automatically |
Deprecated/outdated:
- No deprecated approaches — this phase introduces new capabilities not previously available in the system.
Assumptions Log
| # | Claim | Section | Risk if Wrong |
|---|---|---|---|
| A1 | hindsight_recall tool is available in Hermes cron agent context |
Architecture Patterns — Jira-session mapping | Low — agent can fall back to session_search or export + grep for ticket key patterns |
| A2 | Phase 7 session skill successfully saved session summaries to hindsight with Jira ticket keys | Architecture Patterns | Medium — if session skill was not active for older sessions, those sessions have no hindsight record; daily report would miss their Jira links |
| A3 | 1-to-many session→Jira mapping (one session can update multiple Jira tickets) | Requirements — CRON-03 | Low — depends on how Phase 7 session skill records Jira tickets; the agent can update multiple tickets if it finds multiple keys |
| A4 | All sessions in DB have ended_at set (not just active sessions) |
Patterns — archive script | Low — prune behavior depends on this; if active sessions have ended_at: null, prune may not delete them (which is correct) |
Open Questions (RESOLVED)
-
Does
hermes sessions prune --older-than 30only delete sessions whereended_atis not null? — RESOLVED: Plan 08-01 archive script useshermes sessions exportfirst (captures ALL sessions to JSONL), then runsprune --older-than 30 --yes. If prune only affects ended sessions, active-but-idle sessions are safely preserved. The export captures everything regardless, so no data loss either way. -
Does
session_searchtool work in cron agent context? — RESOLVED: Plan 08-01 daily report cron prompt instructs agent to usehermes sessions export -(JSONL to stdout) as the primary data source, withhindsight_recallfor Jira-session mapping. No dependency onsession_searchavailability in cron context. -
How does the agent determine "active" vs "stale"? — RESOLVED: The daily report prompt tells the agent to use
hermes sessions export -and parse the JSONL output (via python3 in Docker) to filter sessions bylast_activetimestamp. Stale =last_active> 30 days. Active =last_active< 24h.
Environment Availability
| Dependency | Required By | Available | Version | Fallback |
|---|---|---|---|---|
hermes CLI |
All cron jobs | ✓ | v0.16.0 | — |
| Hermes gateway | Cron scheduler | ✓ | Running (PID 3178) | — |
ngn-jira script |
Daily report Jira comments | ✓ | ~/.hermes/scripts/ngn-jira | — |
bash |
Archive script | ✓ | system | — |
date command |
Archive filename timestamp | ✓ | system | — |
mkdir |
Archive directory creation | ✓ | system | — |
jq (optional) |
JSONL filtering | ✗ | — | Use python3 -c or grep instead |
python3 |
JSONL parsing (fallback) | ✓ | system | — |
Missing dependencies with no fallback: None — all required tools are available.
Missing dependencies with fallback: jq — the archive script and cron agents can use python3 -c for JSONL parsing instead.
Security Domain
security_enforcementnot explicitly disabled; include security considerations.
Applicable ASVS Categories
| ASVS Category | Applies | Standard Control |
|---|---|---|
| V2 Authentication | no | — |
| V3 Session Management | no | — |
| V4 Access Control | no | — |
| V5 Input Validation | no | — |
| V6 Cryptography | no | — |
Known Threat Patterns for Hermes Cron
| Pattern | STRIDE | Standard Mitigation |
|---|---|---|
| Cron job prompt injection | Tampering | Prompt is authored by the implementer and stored in Hermes config; not user-controllable |
| Archive file writes to home dir | Tampering | Script uses $HOME/.hermes/archive/sessions/ — within protected Hermes data directory |
| Jira API token exposure via cron output | Information Disclosure | Cron output delivered to Telegram DM only (not logs). wrap_response: true in config may wrap output, reducing inline token leak risk |
| Unauthorized session deletion | Tampering | approvals.cron_mode: deny — destructive operations require manual approval in gateway; no_agent script's prune --yes should be reviewed for safety |
Specific Security Notes
- Cron output delivery:
--deliver telegramsends to TELEGRAM_HOME_CHANNEL (user's DM). Output is not stored in logs (cron output directory is empty by default). - Archive data sensitivity: JSONL export includes full session transcripts — may contain AWS account IDs, project names, Jira ticket details. Archive files should have the same protection as the Hermes data directory (
~/.hermes/).
Sources
Primary (HIGH confidence)
- Hermes CLI v0.16.0 (local) — All cron and session commands tested directly via terminal
hermes cron create --help— full syntax with all flagshermes sessions export --help— confirmed no--older-thanflaghermes sessions prune --help— confirmed--older-thanand--yesflagshermes sessions list --help— confirmed table output only, no--jsonhermes cron edit --help— confirmed--add-skill,--remove-skill,--agent,--no-agentflags
- Session JSONL export — Full session schema inspected:
id,source,title,last_active,archived,message_count,messages,model, token/cost data - System timezone — Confirmed UTC+8 (SGT):
date +%Z→+08 - Cron job creation test — Created test job with
--deliver telegram, confirmed "Next run: 2026-06-16T09:00:00+08:00"
Secondary (MEDIUM confidence)
- CONTEXT.md — Locked decisions from user discussion (D-01 through D-19, discretion areas)
- Phase 7 session skill (
~/.hermes/skills/ngn-agent/session/SKILL.md) — Jira ticket creation pattern, hindsight summary format - Phase 4 jira-query skill (
~/.hermes/skills/ngn-agent/jira/SKILL.md) — Jira API call patterns ~/.hermes/config.yaml—TELEGRAM_HOME_CHANNEL,cron:section,timezone:''
Tertiary (LOW confidence) — None used
Metadata
Confidence breakdown:
- Standard stack: HIGH — All tools verified directly against Hermes CLI
- Architecture: HIGH — Patterns confirmed by user decisions and system capabilities
- Pitfalls: HIGH — Each pitfall verified against actual CLI behavior vs CONTEXT.md assumptions
Research date: 2026-06-15 Valid until: 2026-07-15 (Hermes is actively developed; CLI flags may change in future releases)