# Comprehensive Hermes Environment Audit — Template

Use when the user asks for a "complete end-to-end audit" or "fastest, cleanest, most reliable Hermes setup."

## Audit Phases

### Phase 0: YAML Pre-Flight (MANDATORY — run before any Python yaml.safe_load on config)

A single malformed block in `config.yaml` causes the gateway to silently fall back to defaults.
If config parsing fails, **every user override is ignored**: model routing, fallback chain,
skills disabled list, streaming settings. Symptoms: DeepSeek not firing, local models not
selectable, fallback chain missing, model switch persistence failing.

**Detection:**
```bash
hermes config check 2>&1 | grep -i 'failed to parse'
hermes doctor        # → "could not validate model/provider config"
```

**Common broken-shape found in the wild:**
```yaml
display:
  ...
  personality: concise
  platforms: {}          # ← flow mapping closed here
    discord:             # ← but nested keys follow → INVALID YAML
      streaming: false
    telegram:
      streaming: true
  reasoning_full: false
```

**Fix (atomic Python writer — patch/guard blocks direct edit):**
```python
import yaml, shutil
from pathlib import Path
src = Path('/home/rurouni/.hermes/config.yaml')
shutil.copy2(src, src.with_suffix('.yaml.bak'))          # backup first
with open(src) as f:
    cfg = yaml.safe_load(f)
# remove the broken key; platform streaming belongs under top-level `platforms:`
cfg.get('display', {}).pop('platforms', None)
with open(src, 'w') as f:
    yaml.dump(cfg, f, default_flow_style=False, sort_keys=False, allow_unicode=True)
# verify
with open(src) as f:
    yaml.safe_load(f)
print('Config parses OK')
```

**Platform streaming removal:** Telegram/Discord streaming config lives under the `platforms:` key
at the top level, not under `display:`. When removing a platform, check BOTH `config.yaml`
and `~/.hermes/gateway.json` (if it exists) before assuming the platform is fully gone.

**After ANY config fix:** `hermes gateway restart` is REQUIRED. Model switch persistence
failures (`Failed to persist model switch: while parsing a block mapping`) are a direct
consequence of broken config and resolve on restart.

### Phase 1: Environment Inspection (parallel discovery)

Collect everything simultaneously — filesystem, config, memory, skills, cron:

```bash
# Config
cat ~/.hermes/config.yaml

# File map (all .yaml/.json/.md/.toml under ~/.hermes)
find ~/.hermes -maxdepth 2 -type f \( -name "*.yaml" -o -name "*.yml" -o -name "*.json" -o -name "*.md" \) | head -100

# Skills
ls -la ~/.hermes/skills/
wc -c ~/.hermes/.skills_prompt_snapshot.json

# Memory
wc -c ~/.hermes/memories/*.md
wc -c ~/.hermes/SOUL.md ~/.hermes/AGENTS.md

# Profiles
for p in ~/.hermes/profiles/*/; do echo "--- $(basename $p) ---"; cat "$p/config.yaml" 2>/dev/null | head -60; done

# Cron
cat ~/.hermes/cron/jobs.json

# Scripts
cat ~/.hermes/scripts/models.py
cat ~/.hermes/scripts/model-health-watchdog.py
```

### Phase 2: Token Quantification

Calculate actual token costs using Python:

```python
import json, os, yaml

# Skills manifest size
manifest_path = os.path.expanduser("~/.hermes/.skills_prompt_snapshot.json")
with open(manifest_path) as f:
    data = json.loads(f.read())
manifest_size = sum(v[1] for v in data.get("manifest", {}).values() if len(v) == 2)
print(f"Skills manifest: {manifest_size:,}B (~{manifest_size//4:,} tokens)")

# SOUL.md + AGENTS.md
for f in ["SOUL.md", "AGENTS.md"]:
    path = os.path.expanduser(f"~/.hermes/{f}")
    sz = os.path.getsize(path)
    print(f"{f}: {sz:,}B (~{sz//4:,} tokens)")

# Memory limits vs actuals
config = yaml.safe_load(open(os.path.expanduser("~/.hermes/config.yaml")))
mem_limit = config.get("memory", {}).get("memory_char_limit", 3000)
user_limit = config.get("memory", {}).get("user_char_limit", 1800)
mem_actual = os.path.getsize(os.path.expanduser("~/.hermes/memories/MEMORY.md"))
user_actual = os.path.getsize(os.path.expanduser("~/.hermes/memories/USER.md"))
print(f"MEMORY.md: {mem_actual}/{mem_limit} chars ({mem_actual/mem_limit*100:.0f}%)")
print(f"USER.md: {user_actual}/{user_limit} chars ({user_actual/user_limit*100:.0f}%)")

# Enabled skills count
disabled = set(config.get("skills", {}).get("disabled", []))
enabled = 0
total_size = 0
for root, dirs, files in os.walk(os.path.expanduser("~/.hermes/skills")):
    for f in files:
        if f == "SKILL.md":
            name = os.path.basename(os.path.dirname(os.path.join(root, f)))
            if name not in disabled and not name.startswith('.'):
                enabled += 1
                total_size += os.path.getsize(os.path.join(root, f))
print(f"Enabled skills: {enabled}, total: {total_size:,}B (~{total_size//4:,} tokens)")
```

### Phase 3: Deep Research (parallel subagents)

Spawn 3 parallel research agents:

1. **Hermes docs + GitHub** — Official docs (llms-full.txt), issues, PRs for optimization techniques
2. **Competitive analysis** — Claude Code, OpenCode, Cursor, Aider, Cline, Roo Code, OpenHands, Continue
3. **Prompt engineering research** — Anthropic/OpenAI guides, DSPy, APE, LLMLingua, Gisting

Each uses `toolsets: ["web", "terminal"]`. Cross-reference findings against each other.

### Phase 4: Skills Audit

Classify every enabled skill:
- **Essential**: Loaded regularly, central to user workflow → keep
- **Useful**: Used in specific scenarios → keep, add conditional activation metadata
- **Situational**: Rarely used, toolset/platform-gated → keep disabled, load on-demand
- **Redundant/Overlapping**: Duplicates another skill → merge or disable
- **Obsolete**: Platform mismatch, never relevant → disable

Check for: giant SKILL.md files (>15KB) that should use references/, missing conditional activation (`requires_toolsets`, `platforms`), community must-have skills not present.

### Phase 5: Memory Audit

Check each file for: quality (specific vs vague), relevance (current vs stale), duplication (same facts across files), growth pattern (trending up?). Verify MEMORY.md + USER.md are within configured limits. Check if USER.md has drifted into project documentation (common anti-pattern).

### Phase 6: Prompt Optimization

- Check for redundant behavioral directives across SOUL.md, built-in guidance blocks, and personality overlay
- Verify compression provider routing (should be flash model, not main)
- Verify auxiliary model routing (6 slots often default to `auto` → inherits reasoning model)
- Check delegation model routing
- Verify `tools.stub_mode` enabled
- Check `compression.threshold` appropriate for model context window size

### Phase 7: Performance Analysis

Identify bottlenecks: skills manifest processing, tool schema overhead, delegation model cost, auxiliary task latency, context compression frequency.

### Phase 8: Competitive Analysis

Map against: Claude Code (CLAUDE.md, subagents, auto memory), Aider (RepoMap, ChatSummary, diff editing), Cline (per-model prompts, Focus Chain, Memory Bank), Roo Code (progressive skills, anti-conversational rules).

### Phase 9: Report Structure

1. Executive Summary (grade, critical numbers table)
2. Current State (strengths + weaknesses)
3. Token Efficiency Audit (waste sources table with estimates)
4. Skills Audit (classification + size analysis + gaps)
5. Memory Audit (quality, limits, duplication)
6. Prompt & Context Optimization (assembly analysis + cache utilization)
7. Performance Analysis (bottlenecks + routing + tools)
8. Competitive Analysis (comparison table + top patterns to adopt)
9. Architecture Recommendations (quick wins + short-term + medium-term + long-term)
10. Reliability Improvement Plan
11. Implementation Roadmap (phased with exact commands/configs)
12. Verification Checklist

## Key Metrics to Always Check

| Metric | Target | Red Flag |
|--------|--------|----------|
| Skills manifest size | <500KB | >1MB |
| Enabled skills count | 20-25 | >40 |
| USER.md % of limit | <80% | >100% (silent write block) |
| MEMORY.md % of limit | <80% | >90% |
| SOUL.md size | <500 tokens | >800 tokens |
| AGENTS.md size | <1K tokens | >2K tokens |
| Auxiliary model routing | Explicit flash model | `auto` (inherits main) |
| tools.stub_mode | `true` | not set |
| compression.threshold | 0.50 (128K ctx) | 0.35 (too aggressive) |
| Config version | matches `hermes --version` | >2 versions behind |

## Pitfalls

- Don't rely on a single research source — cross-reference at least 3 for every recommendation
- Skills audit must use session_search evidence AND filesystem inspection — sessions DB can be empty after crash
- Memory write rejection is silent — always verify file sizes, not just tool return values
- The skills manifest is the #1 bloat source but hardest to notice (it's cached, so latency doesn't spike until context fills)
- User profile drifting into project docs is the most common cause of memory write blocks
