o9k-config

View and change hmem memory settings, hooks, sync, and checkpoints. Use on /o9k-config, or when the user asks why context is huge, how to change auto-save, how often checkpoints fire, or how to set up sync.

10 stars

Best use case

o9k-config is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

View and change hmem memory settings, hooks, sync, and checkpoints. Use on /o9k-config, or when the user asks why context is huge, how to change auto-save, how often checkpoints fire, or how to set up sync.

Teams using o9k-config should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/o9k-config/SKILL.md --create-dirs "https://raw.githubusercontent.com/Bumblebiber/hmem/main/skills/o9k-config/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/o9k-config/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How o9k-config Compares

Feature / Agento9k-configStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

View and change hmem memory settings, hooks, sync, and checkpoints. Use on /o9k-config, or when the user asks why context is huge, how to change auto-save, how often checkpoints fire, or how to set up sync.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# o9k-config — View and Change Settings

This skill guides you through reading, explaining, and updating hmem's configuration. The config controls how memory is stored, displayed, checkpointed, and synced across devices.

## Locate and read the config

The config lives at `hmem.config.json` in the same directory as your .hmem file. Located at `~/.hmem/hmem.config.json` (in the same directory as your .hmem file).

Read the file directly — don't ask the user where it is. If it doesn't exist, offer to create one (only non-default values need to be specified).

The config uses a unified format with a `"memory"` block and an optional `"sync"` block:

```json
{
  "memory": { ... },
  "sync": { ... }
}
```

## Show current settings

Present a table of current values vs. defaults. Only highlight values that differ from defaults — the user cares about what they've customized, not the full list.

### Core parameters

| Parameter | Default | Purpose |
|-----------|---------|---------|
| `maxCharsPerLevel` | [200, 2500, 10000, 25000, 50000] | Character limits per tree level [L1–L5]. L1 is always loaded at startup, so keeping it short saves tokens across every session. L5 is raw data, rarely accessed. |
| `maxDepth` | 5 | Tree depth (1–5). Most users need 5. Lower values save storage but lose granularity. |
| `defaultReadLimit` | 100 | Max entries per bulk read. Lower = faster startup, higher = more complete overview. |
| `maxTitleChars` | 50 | Auto-extracted title length. Only applies to entries without explicit body separation — entries with a blank-line body use the first line as title verbatim. Titles are navigation labels — too short truncates meaning, too long wastes space. |
| `accessCountTopN` | 5 | Entries with highest access count get [★] and auto-expand in bulk reads. These are "organic favorites" — the things the agent keeps coming back to. |

### Checkpoint and session parameters (v5+)

These control the automatic knowledge extraction pipeline:

| Parameter | Default | Purpose |
|-----------|---------|---------|
| `checkpointMode` | `"remind"` | **`"auto"`** spawns a Haiku subagent in the background every N exchanges — it reads the conversation, extracts lessons/errors/decisions, and writes them via MCP tools. The main agent is never interrupted. **`"remind"`** injects a prompt asking the main agent to save manually — simpler but interrupts flow. |
| `checkpointInterval` | 20 | Exchanges between checkpoints. Counted in the active O-entry, not per session — so 10 messages on your laptop + 10 on your server = checkpoint fires at 20. Set to 0 to disable. |
| `recentOEntries` | 10 | How many recent session logs to show when loading a project. All entries include full user/agent exchanges (L4/L5), not just titles. Higher = more context but more tokens at project load. |
| `contextTokenThreshold` | 100000 | When cumulative hmem output exceeds this, the agent is told to flush context and /clear. Prevents runaway token usage in long sessions. Set to 0 to disable. |

### Entry schemas (v6.3.0+)

Define per-prefix section schemas that control `create_project` structure and `load_project` rendering depth. When a schema is defined, it replaces the hardcoded R0009 sections and the `loadProjectExpand` settings.

```json
{
  "memory": {
    "schemas": {
      "P": {
        "sections": [
          { "name": "Overview",    "loadDepth": 3, "defaultChildren": ["Current state", "Goals", "Environment"] },
          { "name": "Codebase",    "loadDepth": 1 },
          { "name": "Protocol",    "loadDepth": 0 },
          { "name": "Next Steps",  "loadDepth": 3 }
        ],
        "createLinkedO": true
      }
    }
  }
}
```

| Field | Type | Description |
|-------|------|-------------|
| `sections[].name` | string | L2 section title. Used for matching during auto-reconcile (case-insensitive). |
| `sections[].loadDepth` | 0-4 | 0=skip, 1=title only, 2=+L3 titles, 3=+L3 body, 4=full subtree |
| `sections[].defaultChildren` | string[] | L3 nodes created by `create_project`. Optional. |
| `createLinkedO` | boolean | Auto-create matching O-entry on `create_project`. Default: false. |

**Auto-reconcile:** On every `load_project`, missing schema sections are automatically added as empty L2 nodes. Extra sections not in the schema are kept (loaded at depth 1).

**No schema defined:** Falls back to hardcoded R0009 behavior and `loadProjectExpand` settings.

### load_project display (legacy, pre-v6.3.0)

Only used when no `schemas` entry exists for the prefix. Controls which P-entry sections are expanded:

| Parameter | Default | Purpose |
|-----------|---------|---------|
| `loadProjectExpand.withBody` | `[1]` | L2 section seq numbers where L3 children show title + body content. Default: `.1 Overview` — shows full architecture/state/goals detail. |
| `loadProjectExpand.withChildren` | `[6, 8]` | L2 section seq numbers where all L3 children are listed as titles. Default: `.6 Bugs`, `.8 Open Tasks` — all items visible at a glance. |

Sections not in either list show L3 titles only in compact mode.

### Bulk-read tuning

The bulk-read algorithm decides which entries get expanded (full L2 detail) vs. compressed (title only). Most users don't need to touch these — the defaults work well up to ~500 entries.

| Parameter | Default | Purpose |
|-----------|---------|---------|
| `bulkReadV2.topNewestCount` | 5 | Newest entries expanded. Increase if you want more recent context at startup. |
| `bulkReadV2.topAccessCount` | 3 | Most-accessed entries expanded (time-weighted: `access_count / log2(age_days + 2)`). |
| `bulkReadV2.topObsoleteCount` | 3 | Obsolete entries kept visible — "biggest mistakes" are still worth seeing. |
| `bulkReadV2.topSubnodeCount` | 3 | Entries with most children expanded. These tend to be the most detailed/important. |

### Prefixes

Default: P, L, T, E, D, M, S, N, H, R, O, I. Custom prefixes are merged with defaults — they don't replace them. Each prefix can have a custom description used as group header in bulk reads.

## Help the user make changes

For each parameter the user wants to change:

1. **Explain the tradeoff** in plain language — what gets better, what gets worse
2. **Show the recommended range** (see below)
3. **Validate** before writing — numbers must be positive, arrays must be valid JSON

### Recommended ranges

| Parameter | Range | Guidance |
|-----------|-------|----------|
| `maxCharsPerLevel[0]` (L1) | 60–300 | Below 60 is too terse for useful summaries. Above 300 wastes tokens on every bulk read — L1 is loaded at every session start. |
| `maxCharsPerLevel[4]` (L5) | 1000–100000 | Raw data storage. Higher allows more verbatim content but L5 is rarely loaded. |
| `maxDepth` | 2–5 | 3 suffices for simple setups. 5 for multi-agent or complex projects. |
| `checkpointMode` | `"auto"` or `"remind"` | Recommend `"auto"` — it's non-disruptive and produces better results because Haiku has MCP access to check for duplicates. Auto-checkpoints also write rolling summaries (`[CP]` nodes) and tag skill-dialog exchanges for filtering. |
| `checkpointInterval` | 0–100 | 20 is a good balance. Lower = more frequent saves (more Haiku cost). 0 = disabled. |
| `recentOEntries` | 0–20 | 10 is the sweet spot. With checkpoint summaries, `load_project` shows summary + recent exchanges only — much more compact than raw exchange dumps. |
| `contextTokenThreshold` | 0–500000 | 100k is recommended for most models. Increase for 1M-context models. |

### Common recipes

**"I want auto-checkpoints":**
```json
{ "memory": { "checkpointMode": "auto", "checkpointInterval": 20 } }
```

**"Startup is too slow / uses too many tokens":**
Reduce `recentOEntries` (e.g., 5), `bulkReadV2.topNewestCount` (e.g., 3), or `maxCharsPerLevel[0]` (e.g., 150).

**"I have 500+ entries and bulk reads are noisy":**
Increase `bulkReadV2.topAccessCount` and decrease `topNewestCount` — favor proven entries over new ones.

## Write the updated config

Write `hmem.config.json` with only non-default values. The config uses a `"memory"` wrapper:

```json
{
  "memory": {
    "checkpointMode": "auto"
  },
  "sync": { ... }
}
```

After writing, tell the user:
- Which values changed
- Changes take effect **immediately** — no restart needed
- `maxCharsPerLevel` only affects new entries (existing entries are not reformatted)

## Check o9k-sync status

Run this check as part of every /o9k-config invocation.

**If installed** (`which o9k-sync`): run `npx o9k-sync status` and show server URL, user ID, last push/pull timestamps, and whether `HMEM_SYNC_PASSPHRASE` is set in `.mcp.json` (needed for auto-sync).

**If not installed**: explain that o9k-sync enables zero-knowledge encrypted cross-device sync (AES-256-GCM, server sees only opaque blobs), and offer to install it:
```bash
npm install -g o9k-sync
npx o9k-sync connect
```

### Sync troubleshooting

| Problem | Fix |
|---------|-----|
| "Config not found" | Run `npx o9k-sync connect` |
| 401 Token verification failed | Passphrase has special chars — set `HMEM_SYNC_PASSPHRASE` in .mcp.json env |
| 0 entries after pull | `HMEM_PATH` filename must match between devices |
| Update | `npm update -g o9k-sync` (always global, never inside a project) |

## Hook configuration on Windows (REQUIRED)

On Windows, hook execution is fragile out of the box. Two issues bite every new user:

**1. Git Bash routing** — On systems with Git for Windows installed, Claude Code may route hook commands through Git Bash (`bash.exe`). Its MSYS2 runtime crashes transiently with `add_item ("\??\C:\Program Files\Git", "/", ...) failed, errno 1` during cygheap init, killing the hook **before the command is even parsed**. Symptom: `UserPromptSubmit hook error` or `Stop hook error` with a bash.exe stacktrace.

**2. Unix inline env-var syntax** — Commands like `HMEM_PATH=C:/... node ...` work in bash but break in cmd.exe and PowerShell. Symptom: `"HMEM_PATH" is not recognized as a command`.

**The fix for Windows users (apply to every hook + statusLine):**

```json
{
  "env": {
    "HMEM_PATH": "C:/Users/<you>/.hmem/Agents/<AGENT>/<AGENT>.hmem"
  },
  "hooks": {
    "UserPromptSubmit": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "node C:/Users/<you>/AppData/Roaming/npm/node_modules/its-over-9k/dist/cli.js hook-startup",
            "shell": "powershell"
          }
        ]
      }
    ],
    "Stop": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "node C:/Users/<you>/AppData/Roaming/npm/node_modules/its-over-9k/dist/cli.js log-exchange",
            "shell": "powershell"
          }
        ]
      }
    ],
    "SessionStart": [
      {
        "matcher": "clear",
        "hooks": [
          {
            "type": "command",
            "command": "node C:/Users/<you>/AppData/Roaming/npm/node_modules/its-over-9k/dist/cli.js context-inject",
            "shell": "powershell"
          }
        ]
      }
    ]
  },
  "statusLine": {
    "type": "command",
    "command": "node C:/Users/<you>/AppData/Roaming/npm/node_modules/its-over-9k/dist/cli.js statusline",
    "shell": "powershell"
  }
}
```

Two things to notice:
- `"shell": "powershell"` on **every** hook command and on statusLine — forces native PowerShell, bypasses Git Bash entirely.
- `HMEM_PATH` lives in the top-level `env` block, **not** inline in the command. Claude Code inherits the env block to every hook subprocess, regardless of shell.

**Never use inline env-var syntax in hook commands on Windows.** `VAR=value command` is bash-only syntax and will silently break under cmd.exe or PowerShell.

**Troubleshooting matrix:**

| Symptom | Cause | Fix |
|---------|-------|-----|
| `UserPromptSubmit hook error` (no stacktrace) | Inline `VAR=value` in command + cmd.exe parses it as a command name | Move env vars to `env` block, remove inline prefix |
| `bash.exe: *** fatal error - add_item ... errno 1` | Git Bash MSYS2 runtime crashing at startup | Add `"shell": "powershell"` to every hook command |
| Hooks silently do nothing (no errors) | Wrong shell interpreting the command, or project not active for session logging | Verify `"shell": "powershell"`, call `load_project(id="P00XX")` every session |

**Note on `load_project` per-session:** The `active` flag on a P-entry persists in the database, but the "currently active project for session logging" is a per-session attribute. After every Claude Code restart, the agent must call `load_project(id="P00XX")` again, or exchanges will be logged to O0000 (no-project fallback) instead of the project's O-entry. Consider adding this to your project briefing or session-start routine.

## Hermes Agent Hook Configuration

For Hermes Agent (not Claude Code), hmem integration is configured via
`~/.hermes/config.yaml` hooks and the `hermes-hooks/` scripts shipped
in the its-over-9k repo.

### Required hooks

```yaml
hooks:
  pre_llm_call:
    - command: "~/.hermes/agent-hooks/o9k-startup.sh"
      timeout: 10
  post_llm_call:
    - command: "~/.hermes/agent-hooks/o9k-log-exchange.sh"
      timeout: 10
  on_session_end:
    - command: "/bin/bash -c 'exec hmem checkpoint'"
      timeout: 120
hooks_auto_accept: true
```

### Hook scripts

| Script | Type | Purpose |
|--------|------|---------|
| `o9k-startup.sh` | pre_llm_call | 🟢/🔴 Sync-Status, Projekt-Liste, session_id-Cache für Statusline |
| `o9k-log-exchange.sh` | post_llm_call | Exchange-Logging an aktiven O-Entry via `hmem log-exchange` |
| `hmem-statusline.sh` | Statusbar | Device \| Projekt → O-Node \| Checkpoint-Counter |

### Statusline (CC-Style in Hermes CLI)

To show hmem info in Hermes' status bar (like Claude Code's statusline):

1. Apply the CLI patch:
   ```bash
   cd ~/.hermes/hermes-agent
   git apply ~/projects/hmem/hermes-hooks/hermes-cli-hmem-statusline.patch
   ```

2. Restart Hermes. The status bar will show:
   ```
   Strato Server | P0048 its-over-9k → O0048.118 | 3/5 | ⚕ model | ...
   ```

The statusline requires `hmem statusline` to be installed and the
`o9k-startup.sh` hook to be active (for session_id caching).

### Deployment

On update or fresh install:
```bash
cp ~/projects/hmem/hermes-hooks/*.sh ~/.hermes/agent-hooks/
chmod +x ~/.hermes/agent-hooks/*.sh
```

### Troubleshooting

| Symptom | Cause | Fix |
|---------|-------|-----|
| Statusleiste zeigt kein hmem | CLI-Patch nicht angewandt | `git apply hermes-cli-hmem-statusline.patch` |
| O-Node fehlt in Statusbar | session_id-Cache nicht geschrieben | o9k-startup.sh hook prüfen |
| 🔴 Sync offline | `hmem sync status` schlägt fehl | `hmem sync status` manuell testen |
| Hook-Scripts werden nicht ausgeführt | hooks_auto_accept: false | Setze `hooks_auto_accept: true` in config.yaml |

Related Skills

We are still matching the closest adjacent skills for this page. In the meantime, continue through the full directory.