Files
ngn-agent/.planning/phases/08-cron-reporting/08-01-PLAN.md
Bagas Purwa Sentika 2be5783897 docs(08): create phase 8 cron reporting plans
- 08-01-PLAN.md: Archive script (DRY_RUN toggle) + daily report cron (skill-backed)
- 08-02-PLAN.md: Weekly stale summary cron + weekly archive cron (no_agent)
- ROADMAP.md: Updated Phase 8 plans count to 2

Covers CRON-01 (daily report), CRON-02 (stale archive script+cron),
CRON-03 (Jira integration in daily/weekly reports).
2026-06-15 22:39:18 +08:00

13 KiB

phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, user_setup, must_haves
phase plan type wave depends_on files_modified autonomous requirements user_setup must_haves
08-cron-reporting 01 execute 1
~/.hermes/scripts/archive-stale-sessions.sh
~/.hermes/archive/sessions/
true
CRON-01
CRON-02
truths artifacts key_links
Archive stale sessions script exists at ~/.hermes/scripts/archive-stale-sessions.sh and is executable
Archive directory exists at ~/.hermes/archive/sessions/
Daily report cron job 'ngn-daily-report' is registered and fires at 09:00 SGT
Daily report loads both 'session' and 'jira-query' skills
path provides min_lines must_contain
~/.hermes/scripts/archive-stale-sessions.sh Deterministic no_agent script for session export + prune 35
DRY_RUN
hermes sessions export
hermes sessions prune --older-than 30 --yes
path provides
~/.hermes/archive/sessions/ Archive storage directory for stale session JSONL exports
path provides
Hermes cron DB (job: ngn-daily-report) Daily report cron job entry in Hermes cron scheduler
from to via pattern
archive-stale-sessions.sh hermes sessions export CLI call with positional output path hermes sessions export
from to via pattern
archive-stale-sessions.sh hermes sessions prune CLI call with --older-than 30 --yes hermes sessions prune --older-than 30 --yes
from to via pattern
ngn-daily-report cron job session skill --skill session in cron create skill session
from to via pattern
ngn-daily-report cron job jira-query skill --skill jira-query in cron create skill jira-query
Create the archive script and register the daily report cron job.

Purpose: Lay the foundation for CRON-02 (stale session archive script) and implement CRON-01 + CRON-03 (daily report with Jira integration). The archive script is created with a dry-run toggle so the first archive fires in safe mode (export only, no prune). The daily report cron is a skill-backed job that loads the session and jira-query skills to enumerate active sessions, post Jira progress comments, and deliver a Telegram summary.

Output:

  • ~/.hermes/scripts/archive-stale-sessions.sh — no_agent archive script with DRY_RUN toggle
  • ~/.hermes/archive/sessions/ — archive storage directory
  • Hermes cron job ngn-daily-report registered in gateway scheduler

<execution_context> @/Users/bapung/.config/opencode/gsd-core/workflows/execute-plan.md @/Users/bapung/.config/opencode/gsd-core/templates/summary.md </execution_context>

@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/REQUIREMENTS.md @.planning/phases/08-cron-reporting/08-CONTEXT.md @.planning/phases/08-cron-reporting/08-RESEARCH.md @/Users/bapung/.hermes/config.yaml @/Users/bapung/.hermes/skills/ngn-agent/session/SKILL.md @/Users/bapung/.hermes/skills/ngn-agent/jira/SKILL.md @.planning/phases/07-main-session-skill/07-01-SUMMARY.md Task 1: Create archive-stale-sessions.sh with dry-run toggle + archive directory ~/.hermes/scripts/archive-stale-sessions.sh ~/.hermes/archive/sessions/ Create the archive directory and the no_agent archive script.
**Archive directory:**
```bash
mkdir -p ~/.hermes/archive/sessions
```

**Script file:** Create `~/.hermes/scripts/archive-stale-sessions.sh` with:
- `DRY_RUN=true` at top — safe default (export only, skip prune)
- `set -euo pipefail` for strict error handling
- `ARCHIVE_DIR="$HOME/.hermes/archive/sessions"` — archive location per D-12
- `mkdir -p "$ARCHIVE_DIR"` — ensure directory exists
- `TIMESTAMP=$(date +%Y%m%d_%H%M%S)` for unique filenames
- `OUTPUT_FILE="$ARCHIVE_DIR/sessions-${TIMESTAMP}.jsonl"` — date-stamped per D-11 corrected (export uses positional output arg, no `--output` flag — per RESEARCH.md Pitfall 1 and CLI verification)
- Step 1: `hermes sessions export "$OUTPUT_FILE"` — exports ALL sessions (no `--older-than` flag on export — per D-11 correction and RESEARCH.md §Critical finding)
- Step 2: Only if `$DRY_RUN = false`, run `hermes sessions prune --older-than 30 --yes` (uses `--yes` not `--confirm` — confirmed by RESEARCH.md Pitfall 2 and `hermes sessions prune --help`)
- Step 3: `hermes sessions stats` — show post-archive store state
- Echo progress messages for Telegram delivery (stdout is delivered verbatim via `--deliver telegram`)
- Print summary with session count and file size

**Critical corrections from research (must NOT repeat CONTEXT.md errors):**
- ❌ `hermes sessions export --older-than 30d --output <path>` — DOES NOT EXIST. Use positional path only.
- ❌ `hermes sessions prune --confirm` — DOES NOT EXIST. Use `--yes`.
- ✅ Export all, prune separate: `hermes sessions export <path> && hermes sessions prune --older-than 30 --yes`

After creating the file, make it executable:
```bash
chmod +x ~/.hermes/scripts/archive-stale-sessions.sh
```

**Dry-run verification:** Script's default mode is export-only (DRY_RUN=true). User manually reviews the first JSONL export before setting DRY_RUN=false to enable pruning. This satisfies the user's discretion requirement for safe initial testing.
test -f ~/.hermes/scripts/archive-stale-sessions.sh \ && test -x ~/.hermes/scripts/archive-stale-sessions.sh \ && test -d ~/.hermes/archive/sessions \ && grep -q 'DRY_RUN' ~/.hermes/scripts/archive-stale-sessions.sh \ && grep -q 'hermes sessions export' ~/.hermes/scripts/archive-stale-sessions.sh \ && grep -q 'hermes sessions prune --older-than 30' ~/.hermes/scripts/archive-stale-sessions.sh \ && grep -q '--yes' ~/.hermes/scripts/archive-stale-sessions.sh \ && grep -q 'set -euo pipefail' ~/.hermes/scripts/archive-stale-sessions.sh Archive script exists at ~/.hermes/scripts/archive-stale-sessions.sh, is executable, and contains: - DRY_RUN=true toggle (safe default) - Export with date-stamped filename - Prune with `--older-than 30 --yes` (gated behind dry-run) - `set -euo pipefail` error handling - Progress echo statements for Telegram delivery Archive directory exists at ~/.hermes/archive/sessions/ Task 2: Register daily report cron job (09:00 SGT, skill-backed) (Hermes cron DB — internal state) Register the daily report cron job using `hermes cron create`.
**Command (execute verbatim):**
```bash
hermes cron create \
  --name "ngn-daily-report" \
  --deliver telegram \
  --skill session \
  --skill jira-query \
  "0 9 * * *" \
  "Daily operational report — generate summary of active sessions and update their Jira tickets:

1. DISCOVER ACTIVE SESSIONS: Run 'hermes sessions export -' to get all sessions as JSONL. Use python3 to parse the JSONL and find sessions with last_active within the last 7 days — these are the active sessions. For each active session, record its id, title, and last_active timestamp. (Note: 'hermes sessions list' has NO --json flag — use export - for machine-readable output per RESEARCH.md Pitfall 3.)

2. FIND JIRA TICKETS: For each active session, use hindsight_recall with query 'session summary jira' to find the Jira ticket key from the session summary saved by Phase 7's session skill (Step 7, tier: session-summary). If hindsight_recall returns no results, search session messages from the export output for Jira ticket key patterns (PLATFORM-<digits>, AIOPS-<digits>, etc.) — per RESEARCH.md Pitfall 4. One session may have multiple Jira tickets (1-to-many mapping — D-04).

3. UPDATE JIRA TICKETS: For each active session with found Jira ticket key(s), add a progress comment via:
   ngn-jira POST '/rest/api/3/issue/<KEY>/comment' --body '{\"body\": \"Session activity update — Date: <today>, Last active: <last_active>. Session: <session_id>. Progress: See session transcript for details.\"}'
   IMPORTANT: Do NOT transition ticket statuses (D-05). Only add comments. Do NOT update tickets for stale sessions (D-15).

4. COMPOSE TELEGRAM SUMMARY: Create a structured message with sections:
   📋 ACTIVE SESSIONS — list each with title, last active timestamp
   🔄 JIRA UPDATED — list of ticket keys that received new comments
   Keep within Telegram's 4096 character limit.
   Do NOT include stale session info or ticket status transitions.

5. DELIVERY: Your response is automatically delivered to TELEGRAM_HOME_CHANNEL via --deliver telegram."
```

**Key details (per locked decisions):**
- Per D-01: Schedule `0 9 * * *` = daily at 09:00 SGT. Timezone is already SGT (+08, confirmed by date +%Z) — no TZ config needed per RESEARCH.md Pitfall 5.
- Per D-06: `--deliver telegram` sends to TELEGRAM_HOME_CHANNEL (474440517)
- Per D-17: Skill-backed cron (two `--skill` flags, no `--no-agent`)
- Per D-18: Loads `session` skill (Phase 7) for session structure + `jira-query` skill (Phase 4) for Jira comment patterns
- Per D-04/D-14: Updates ALL Jira tickets linked to active sessions (1-to-many mapping)
- Per D-05/D-16: Comments only, no status transitions
- Per D-07: Report includes active sessions list, last activity timestamps, Jira ticket keys updated
</action>
hermes cron list 2>&1 | grep -q ngn-daily-report Daily report cron job `ngn-daily-report` is registered with: - Schedule: `0 9 * * *` (daily at 09:00) - Delivery: telegram (TELEGRAM_HOME_CHANNEL) - Skills: session + jira-query (skill-backed, no no-agent) - Prompt instructs agent to: enumerate active sessions via JSONL export, find Jira tickets via hindsight_recall, add progress comments via ngn-jira, compose Telegram summary

<threat_model>

Trust Boundaries

Boundary Description
Cron agent → Hermes session DB Cron LLM agent reads session data (ids, titles, timestamps, transcripts) to compose reports
Cron agent → Jira Cloud API Cron LLM agent writes progress comments to Jira tickets via ngn-jira script
no_agent script → Hermes session DB Archive script reads (export) and writes (prune) session store directly

STRIDE Threat Register

Threat ID Category Component Disposition Mitigation Plan
T-08-01 Tampering Daily report cron prompt accept Cron prompt is authored during plan execution and stored in Hermes cron DB — not user-controllable. No injection risk.
T-08-02 Information Disclosure Archive JSONL files mitigate Archive directory (~/.hermes/archive/sessions/) is under ~/.hermes/ which has same protection as Hermes data dir. No world-readable permissions.
T-08-03 Information Disclosure Cron output to Telegram accept Report summaries sent to user's DM channel only (TELEGRAM_HOME_CHANNEL). No PII in summaries — session IDs and Jira keys only.
T-08-04 Tampering Session prune via no_agent script mitigate DRY_RUN=true by default — no prune until user explicitly sets false. Also approvals.cron_mode: deny in config adds an approval gate for destructive cron operations per RESEARCH.md Security Domain.
T-08-05 Elevation of Privilege Jira comment injection accept Cron agent uses ngn-jira script which authenticates with JIRA_EMAIL + JIRA_API_TOKEN — bounded to the user's Jira permissions. Comments only, no transitions per D-05/D-16.
T-08-SC Tampering Package installs n/a No packages installed — all tools are native Hermes CLI or existing scripts.
</threat_model>
1. `test -f ~/.hermes/scripts/archive-stale-sessions.sh && test -x ~/.hermes/scripts/archive-stale-sessions.sh` — script exists and is executable 2. `test -d ~/.hermes/archive/sessions` — archive directory exists 3. `grep -q DRY_RUN ~/.hermes/scripts/archive-stale-sessions.sh` — dry-run toggle present 4. `grep -q 'hermes sessions export' ~/.hermes/scripts/archive-stale-sessions.sh && grep -q 'hermes sessions prune --older-than 30 --yes' ~/.hermes/scripts/archive-stale-sessions.sh` — correct CLI commands used 5. `hermes cron list 2>&1 | grep -q ngn-daily-report` — daily report cron job registered 6. `hermes cron run ngn-daily-report 2>&1` — test-run succeeds (schedules for immediate execution; verify no errors)

<success_criteria>

  • Archive script at ~/.hermes/scripts/archive-stale-sessions.sh is executable with DRY_RUN=true default
  • Archive directory at ~/.hermes/archive/sessions/ exists
  • Daily report cron job ngn-daily-report is registered and visible in hermes cron list
  • Daily report uses correct schedule (0 9 * * *), delivery (telegram), and skills (session + jira-query)
  • Test-run of daily report cron job completes without CLI errors </success_criteria>
Create `.planning/phases/08-cron-reporting/08-01-SUMMARY.md` when done.