- 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).
202 lines
10 KiB
Markdown
202 lines
10 KiB
Markdown
---
|
|
phase: 08-cron-reporting
|
|
plan: 02
|
|
type: execute
|
|
wave: 2
|
|
depends_on:
|
|
- 08-01
|
|
files_modified: []
|
|
autonomous: true
|
|
requirements:
|
|
- CRON-02
|
|
- CRON-03
|
|
user_setup: []
|
|
must_haves:
|
|
truths:
|
|
- "Weekly stale summary cron 'ngn-weekly-stale-summary' fires at Sunday 20:00 SGT"
|
|
- "Weekly archive cron 'ngn-weekly-archive' fires at Sunday 20:05 SGT (5 min after summary)"
|
|
- "Weekly stale summary loads 'session' skill for understanding session structure"
|
|
- "Weekly archive runs as no_agent (script archive-stale-sessions.sh, no LLM cost)"
|
|
- "Archive cron schedule is offset by 5 min to avoid race condition with summary"
|
|
artifacts:
|
|
- path: "Hermes cron DB (job: ngn-weekly-stale-summary)"
|
|
provides: "Weekly stale session summary cron entry"
|
|
- path: "Hermes cron DB (job: ngn-weekly-archive)"
|
|
provides: "Weekly archive cron entry"
|
|
key_links:
|
|
- from: "ngn-weekly-stale-summary cron"
|
|
to: "session skill"
|
|
via: "--skill session in cron create"
|
|
pattern: "skill session"
|
|
- from: "ngn-weekly-archive cron"
|
|
to: "archive-stale-sessions.sh"
|
|
via: "--script archive-stale-sessions.sh --no-agent"
|
|
pattern: "archive-stale-sessions"
|
|
- from: "ngn-weekly-archive cron"
|
|
to: "ngn-weekly-stale-summary cron"
|
|
via: "5 minute offset (20:05 vs 20:00) to avoid race condition"
|
|
pattern: "5 20"
|
|
---
|
|
|
|
<objective>
|
|
Register two weekly cron jobs: stale session summary and stale session archive.
|
|
|
|
**Purpose:** Implement CRON-02's weekly archive (complete the stale session lifecycle) and CRON-03's stale session Jira awareness (weekly summary mentions Jira ticket keys for stale sessions). The weekly summary is skill-backed (uses session skill to understand session structure and hindsight for Jira-session mapping discovery). The weekly archive is no_agent (deterministic export + prune via the script created in Plan 1). The 5-minute offset between summary (20:00) and archive (20:05) prevents a race condition where the prune removes sessions the summary agent is still enumerating — per RESEARCH.md Anti-Patterns.
|
|
|
|
**Output:**
|
|
- Hermes cron job `ngn-weekly-stale-summary` registered (Sunday 20:00 SGT)
|
|
- Hermes cron job `ngn-weekly-archive` registered (Sunday 20:05 SGT)
|
|
</objective>
|
|
|
|
<execution_context>
|
|
@/Users/bapung/.config/opencode/gsd-core/workflows/execute-plan.md
|
|
@/Users/bapung/.config/opencode/gsd-core/templates/summary.md
|
|
</execution_context>
|
|
|
|
<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
|
|
@.planning/phases/08-cron-reporting/08-01-SUMMARY.md
|
|
</context>
|
|
|
|
<tasks>
|
|
|
|
<task type="auto">
|
|
<name>Task 1: Register weekly stale session summary cron (Sunday 20:00 SGT, skill-backed)</name>
|
|
<files>(Hermes cron DB — internal state)</files>
|
|
<action>
|
|
Register the weekly stale session summary cron job using `hermes cron create`.
|
|
|
|
**Command (execute verbatim):**
|
|
```bash
|
|
hermes cron create \
|
|
--name "ngn-weekly-stale-summary" \
|
|
--deliver telegram \
|
|
--skill session \
|
|
"0 20 * * 0" \
|
|
"Weekly stale session summary — report on sessions inactive for more than 30 days:
|
|
|
|
1. FIND STALE SESSIONS: Run 'hermes sessions export -' to get all sessions as JSONL. Use python3 to parse and filter for sessions where last_active is more than 30 days ago. For each stale 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. DISCOVER JIRA TICKETS: For each stale session, use hindsight_recall with query 'session summary jira' to find the Jira ticket key from the session summary (saved by Phase 7 session skill, Step 7, tier: session-summary). If hindsight_recall returns no results, search session messages for Jira key patterns (PLATFORM-<digits>, AIOPS-<digits>, etc.).
|
|
|
|
3. REPORT ONLY — NO JIRA MUTATIONS: Do NOT add comments to Jira tickets. Do NOT transition ticket statuses. Only report their keys in the summary (per D-10 and D-15).
|
|
|
|
4. COMPOSE TELEGRAM SUMMARY: Create a structured message with sections:
|
|
⏳ STALE SESSIONS (>30d inactive) — list each with:
|
|
- Session title
|
|
- Last activity date
|
|
- Linked Jira ticket key (or 'no ticket')
|
|
Keep within Telegram's 4096 character limit. Do not include active sessions.
|
|
|
|
5. DELIVERY: Your response is automatically delivered to TELEGRAM_HOME_CHANNEL via --deliver telegram."
|
|
```
|
|
|
|
**Key details (per locked decisions):**
|
|
- Per D-02: Schedule `0 20 * * 0` = Sunday at 20:00 SGT. Timezone is already SGT (+08) — no TZ config needed.
|
|
- Per D-08: Summarizes inactive sessions (>30d since last activity) with session title, last activity date, linked Jira ticket
|
|
- Per D-09: Delivered via Telegram to user's DM channel
|
|
- Per D-10/D-15: No auto-comments on stale tickets — only reported in summary
|
|
- Per D-17: Skill-backed cron (one `--skill session`, no `--no-agent`)
|
|
- Uses `--skill session` (Phase 7) for understanding session structure and transaction patterns
|
|
</action>
|
|
<verify>
|
|
<automated>
|
|
hermes cron list 2>&1 | grep -q ngn-weekly-stale-summary
|
|
</automated>
|
|
</verify>
|
|
<done>
|
|
Weekly stale summary cron `ngn-weekly-stale-summary` is registered with:
|
|
- Schedule: `0 20 * * 0` (Sunday at 20:00 SGT)
|
|
- Delivery: telegram (TELEGRAM_HOME_CHANNEL)
|
|
- Skill: session (skill-backed, no no-agent)
|
|
- Prompt instructs agent to: enumerate stale sessions via JSONL export, discover Jira ticket keys via hindsight_recall, compose Telegram summary without Jira mutations
|
|
</done>
|
|
</task>
|
|
|
|
<task type="auto">
|
|
<name>Task 2: Register weekly archive cron (Sunday 20:05 SGT, no_agent)</name>
|
|
<files>(Hermes cron DB — internal state)</files>
|
|
<action>
|
|
Register the weekly stale session archive cron job using `hermes cron create` with `--no-agent` and `--script` flags.
|
|
|
|
**Command (execute verbatim):**
|
|
```bash
|
|
hermes cron create \
|
|
--name "ngn-weekly-archive" \
|
|
--deliver telegram \
|
|
--script archive-stale-sessions.sh \
|
|
--no-agent \
|
|
"5 20 * * 0"
|
|
```
|
|
|
|
**Key details (per locked decisions):**
|
|
- Per D-03 (corrected): Schedule `5 20 * * 0` = Sunday at 20:05 SGT — 5 minutes after the stale summary. This prevents a race condition where the prune might delete sessions the summary agent is still enumerating (per RESEARCH.md Anti-Pattern: Race condition on same schedule).
|
|
- Per D-11 (corrected): Uses native Hermes commands (`hermes sessions export` + `hermes sessions prune --older-than 30 --yes`). The script was created in Plan 1 (08-01) with all research corrections applied (no --older-than on export, --yes on prune).
|
|
- Per D-12: Archive files stored in `~/.hermes/archive/sessions/sessions-<timestamp>.jsonl`
|
|
- Per D-13: Runs weekly after the stale summary report
|
|
- Per D-19: Uses `--no-agent` for deterministic CLI operations (no LLM cost)
|
|
- The script at `~/.hermes/scripts/archive-stale-sessions.sh` was created in Plan 1 and has `DRY_RUN=true` by default (export only, skip prune). User must manually verify the first export and set DRY_RUN=false to enable pruning.
|
|
</action>
|
|
<verify>
|
|
<automated>
|
|
hermes cron list 2>&1 | grep -q ngn-weekly-archive
|
|
</automated>
|
|
</verify>
|
|
<done>
|
|
Weekly archive cron `ngn-weekly-archive` is registered with:
|
|
- Schedule: `5 20 * * 0` (Sunday at 20:05 SGT — 5 min after summary to avoid race condition)
|
|
- Delivery: telegram (stdout of archive-stale-sessions.sh delivered verbatim)
|
|
- Mode: --no-agent (no LLM cost)
|
|
- Script: archive-stale-sessions.sh (from ~/.hermes/scripts/, created in Plan 1)
|
|
</done>
|
|
</task>
|
|
|
|
</tasks>
|
|
|
|
<threat_model>
|
|
## Trust Boundaries
|
|
|
|
| Boundary | Description |
|
|
|----------|-------------|
|
|
| Cron agent → Hermes session DB | Weekly summary LLM agent reads session data (ids, titles, timestamps) to identify stale sessions |
|
|
| no_agent script → Hermes session DB | Archive script reads (export) and writes (prune) session store directly with CLI permissions |
|
|
|
|
## STRIDE Threat Register
|
|
|
|
| Threat ID | Category | Component | Disposition | Mitigation Plan |
|
|
|-----------|----------|-----------|-------------|-----------------|
|
|
| T-08-06 | Tampering | Weekly stale summary cron prompt | accept | Prompt is authored during plan execution and stored in Hermes cron DB — not user-controllable. No injection risk. |
|
|
| T-08-07 | Repudiation | Stale session prune | mitigate | Archive script's DRY_RUN=true default means no prune until user flips the flag. All exports produce timestamped JSONL files that serve as audit trail of which sessions existed before pruning. |
|
|
| T-08-08 | Denial of Service | Race condition: summary + archive at same time | mitigate | Archive scheduled at 20:05 (5 min after summary at 20:00) — prevents prune-from-underneath during summary enumeration per RESEARCH.md §Anti-Patterns to Avoid. |
|
|
| T-08-SC | Tampering | Package installs | n/a | No packages installed — all tools are native Hermes CLI or existing scripts. |
|
|
</threat_model>
|
|
|
|
<verification>
|
|
1. `hermes cron list 2>&1 | grep -q ngn-weekly-stale-summary` — weekly summary cron job registered
|
|
2. `hermes cron list 2>&1 | grep -q ngn-weekly-archive` — weekly archive cron job registered
|
|
3. `hermes cron list 2>&1 | grep 'ngn-weekly-stale-summary' | grep -q '0 20 \* \* 0'` — correct schedule (Sunday 20:00 SGT)
|
|
4. `hermes cron list 2>&1 | grep 'ngn-weekly-archive' | grep -q '5 20 \* \* 0'` — correct schedule (Sunday 20:05 SGT)
|
|
5. `hermes cron run ngn-weekly-stale-summary 2>&1` — test-run succeeds (schedules for immediate execution; verify no CLI errors)
|
|
6. `hermes cron run ngn-weekly-archive 2>&1` — test-run succeeds (schedules for immediate execution; verify no CLI errors)
|
|
</verification>
|
|
|
|
<success_criteria>
|
|
- Weekly stale summary cron `ngn-weekly-stale-summary` registered with schedule `0 20 * * 0`, delivery telegram, skill session
|
|
- Weekly archive cron `ngn-weekly-archive` registered with schedule `5 20 * * 0`, delivery telegram, no_agent mode, script archive-stale-sessions.sh
|
|
- Both jobs visible in `hermes cron list` with correct schedules
|
|
- Archive cron runs 5 min AFTER summary cron to prevent race condition (per Research Anti-Pattern)
|
|
- Test-run of both cron jobs completes without CLI errors
|
|
</success_criteria>
|
|
|
|
<output>
|
|
Create `.planning/phases/08-cron-reporting/08-02-SUMMARY.md` when done.
|
|
</output>
|