---
name: session-compactor
description: "Use when the user asks to clean up, consolidate, deduplicate, merge, or organize past Hermes (or cross-harness) sessions -- phrases like 'clean up my sessions', 'merge my redundant sessions', 'consolidate sessions about X', 'find duplicate sessions', 'rename my session titles', or 'restore an archived session'. This skill works directly on ~/.hermes/state.db (Hermes's own session database) and never touches code, config, or active work. Always runs dry-run first; --apply does the writes."
---

# Session Compactor

Cleans up Hermes Agent session history by:

1. **`compact`** — finding sessions that are duplicates or continuations of the
   same task and merging them into ONE new session in `~/.hermes/state.db`.
   The new session has a clean title; the user resumes it with
   `hermes -r "<title>"`. Originals are exported to JSON archive, then deleted.
2. **`rename-titles`** — replacing auto-generated junk titles
   (`20260515_100000_dddddd` and the like) with clean LLM-generated titles.
3. **`restore`** — re-inserting an archived JSON file back into state.db.
4. **`dream`** *(optional)* — building a cross-session memory index file
   from compacted digests. Overlaps partially with Hermes's native MEMORY.md
   so usually only used for cross-harness setups.

## When to use this

Trigger on requests like:
- "clean up my sessions" / "consolidate my sessions"
- "find redundant/duplicate sessions"
- "merge the sessions where I worked on X"
- "rename my session titles" / "my session titles are garbage"
- "restore an archived session" / "I need session X back"

Do NOT use this skill for:
- Anything that touches actual code, files outside session storage, or git
- Modifying live MEMORY.md or USER.md (Hermes manages those itself)
- Replacing `hermes sessions prune` for simple age-based deletion (use that)

## How to run it

Always run discovery and a dry-run pass first and show the user the report
before passing `--apply`. Do not skip straight to `--apply` even if the
user's phrasing sounds confident ("yeah just clean it all up"). Once
originals are archived AND deleted from state.db, the recovery path is
manual (run `restore` against the JSON file).

```bash
cd <wherever-this-skill-is-installed>

# 1. Inventory: what's in state.db?
python -m hermes_compactor.cli discover

# 2. (Optional) Clean up junk titles first, dry-run then apply
python -m hermes_compactor.cli rename-titles
python -m hermes_compactor.cli rename-titles --apply

# 3. Heuristic clustering only, no LLM calls yet
python -m hermes_compactor.cli cluster

# 4. Full pipeline dry-run -- shows what would be merged
python -m hermes_compactor.cli compact

# 5. After the user confirms the dry-run looks right:
python -m hermes_compactor.cli compact --apply

# Restore an archived session if needed:
python -m hermes_compactor.cli restore <path-to-archived.json> --apply
```

## Configuration

`config.yaml` controls everything. The defaults assume:
- Hermes is the only enabled source (`sources.hermes.enabled: true`)
- Output target is Hermes (`output.target_tool: hermes`) — consolidated
  sessions get written back to `~/.hermes/state.db`
- LLM backend should be set to `openai_compatible` with the user's chosen
  provider (DeepSeek, local Qwen via llama-swap, etc.)

To enable cross-harness consolidation, flip `sources.opencode.enabled`,
`sources.claude_code.enabled`, etc. to `true` in `config.yaml`.

## Safety properties

- **Archive-before-delete:** every source session is exported to a JSON file
  under `~/.hermes/session-archive/<date>/<id>.json` BEFORE it's removed
  from state.db. The `restore` command re-inserts those JSONs.
- **Lockfile:** `compact` and `dream` share a lockfile so they can't race
  with each other or with a concurrent invocation.
- **Idle-session guard:** sessions modified within the last 2 hours
  (`min_idle_seconds: 7200` default) are skipped — won't merge what you're
  actively working in.
- **Title collisions handled:** Hermes's `UNIQUE INDEX on sessions(title)`
  is honored by auto-suffixing ` #2`, ` #3`, etc. (same convention Hermes
  itself uses).
- **Lineage preserved:** the new consolidated session's `parent_session_id`
  is set to the most recent source session, so it appears as a continuation
  in `hermes sessions list`.
- **Schema-version-defensive:** all DB reads use `PRAGMA table_info()` first
  and only touch columns that exist on this install (Hermes is at schema
  version 11+ and adds columns over time).

## What this skill does NOT do

- Modify Hermes's `~/.hermes/memories/MEMORY.md` or `USER.md` (those are
  agent-managed; we don't touch them).
- Compete with Hermes's built-in FTS5 `session_search` tool (we don't do
  search at all).
- Replace `hermes sessions prune --older-than-days` for plain age-based
  deletion (use that for simple cases).
- Modify any code, config, or files outside `~/.hermes/` and our own
  archive/lock directories.
