o9k-setup

First-time install of hmem: MCP server, skill files, and auto-memory hooks for Claude Code, Gemini CLI, or OpenCode. Use on 'set up memory', 'install hmem', 'initialize hmem', or 'first-time setup'.

10 stars

Best use case

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

First-time install of hmem: MCP server, skill files, and auto-memory hooks for Claude Code, Gemini CLI, or OpenCode. Use on 'set up memory', 'install hmem', 'initialize hmem', or 'first-time setup'.

Teams using o9k-setup 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-setup/SKILL.md --create-dirs "https://raw.githubusercontent.com/Bumblebiber/hmem/main/skills/o9k-setup/SKILL.md"

Manual Installation

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

How o9k-setup Compares

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

Frequently Asked Questions

What does this skill do?

First-time install of hmem: MCP server, skill files, and auto-memory hooks for Claude Code, Gemini CLI, or OpenCode. Use on 'set up memory', 'install hmem', 'initialize hmem', or 'first-time setup'.

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

# hmem Setup

## Recommended: `hmem init`

Install hmem globally, then run the interactive installer:

```bash
npm install -g its-over-9k
hmem init
```

`hmem init` performs all setup steps automatically:
1. Detects installed AI tools (Claude Code, Gemini CLI, OpenCode, Cursor, Windsurf, Cline)
2. Asks for installation scope (system-wide or project-local)
3. Creates the memory directory and optional example database
4. Writes `.mcp.json` with the correct paths for each detected tool
5. Adds session-start instructions to the tool's config file (CLAUDE.md, GEMINI.md, etc.)
6. Creates `hmem.config.json` with sensible defaults
7. Installs all 4 auto-memory hooks (Claude Code only — see Hook Reference below)
8. Copies skill files (slash commands) to the tool's skill directory

After `hmem init`, install the slash-command skills:

```bash
npx hmem update-skills
```

Restart your AI tool and call `read_memory()` to verify.

Non-interactive mode (CI / scripting):

```bash
hmem init --global --tools claude-code --dir ~/.hmem --no-example
```

---

## Hook Reference (Claude Code)

`hmem init` registers 4 hooks in `~/.claude/settings.json`. Each hook is a bash script in `~/.claude/hooks/`.

### 1. UserPromptSubmit — memory load + checkpoint reminder

Script: `~/.claude/hooks/o9k-startup.sh`

- **First message**: injects `additionalContext` telling the agent to call `read_memory()` silently. Also injects H-entries (ID + title; **pinned H-entries include their L2 children inline** so canonical identity/preference info is visible without extra reads — since v1.3.3), active device apps, infrastructure favorites, recent projects, checkpoint status, and an `--- hmem-sync ---` block showing link state (✓ linked / ⚠ partial / ✗ not linked / ✗ not configured). Block is always emitted since v1.2.9.
- **Every Nth message** (N = `checkpointInterval`, default 20): injects a checkpoint reminder.
  - `checkpointMode: "remind"` — adds an `additionalContext` nudge; the agent decides what to save.
  - `checkpointMode: "auto"` — checkpoint is handled by the Stop hook instead (no reminder injected).
- Subagents (messages with `parentUuid`) are skipped.
- Uses a per-session counter file at `/tmp/claude-o9k-counter-{SESSION_ID}`.

### 2. Stop (async) — exchange logging + checkpoint

Script: `~/.claude/hooks/o9k-log-exchange.sh`

- Runs asynchronously after every agent response (timeout: 10s).
- Pipes the Stop hook JSON (containing `transcript_path` and `last_assistant_message`) to `hmem log-exchange`.
- `hmem log-exchange` reads the last user message from the JSONL transcript, combines it with the agent response, and appends both to the currently active O-entry (session history).
- If no active O-entry exists, one is created automatically.
- Every N exchanges (configurable via `checkpointInterval`, default 20), triggers a checkpoint:
  - **auto mode**: Spawns `hmem checkpoint` in background — Haiku subagent with MCP tools that:
    - Titles each exchange with a descriptive summary (max 50 chars)
    - Writes L/D/E entries for non-obvious insights
    - Updates P-entry (protocol, bugs, open tasks, overview, codebase)
    - Writes a checkpoint summary for context re-injection
    - Verifies project relevance and fixes links
  - **remind mode**: Injects a reminder for the main agent to save knowledge manually
- Checks transcript file size and writes a warning flag when context exceeds `contextTokenThreshold` (default 100k tokens).

### 3. SessionStart[clear] — context re-injection + deactivation

Fires only after `/clear` (matcher: `"clear"`). Two hooks run in sequence:

**a) `hmem context-inject`** — outputs `additionalContext` containing:
  - 5 most recently edited P-entries (one line each, active marked with `[*]`)
  - Hint to call `read_memory({prefix:"P", titles_only:true})` for the full list
  - All R-entries (rules, one line each)
  - Footer with `load_project` call for the active project (if any)
  - Keeps the agent oriented after a context reset without a full `read_memory()` call.

**b) `hmem deactivate`** — resets the active project for the new session:
  - Writes a session marker with `projectId: null, deactivated: true` for the new session_id
  - Deletes the per-process active-project file (`/tmp/o9k-active-<pid>.txt`)
  - Clears statusline cache files
  - Result: statusline shows `no project` after `/clear` until `load_project` is called

---

## Configuration Reference

Place `hmem.config.json` in your memory directory (the path you chose during `hmem init`). All keys are optional — defaults are applied for anything missing.

```json
{
  "memory": {
    "maxCharsPerLevel": [200, 2500, 10000, 25000, 50000],
    "maxDepth": 5,
    "defaultReadLimit": 100,
    "maxTitleChars": 50,
    "checkpointInterval": 20,
    "checkpointMode": "remind",
    "recentOEntries": 10,
    "contextTokenThreshold": 100000,
    "bulkReadV2": {
      "topAccessCount": 3,
      "topNewestCount": 5,
      "topObsoleteCount": 3,
      "topSubnodeCount": 3,
      "newestPercent": 20,
      "newestMin": 5,
      "newestMax": 15,
      "accessPercent": 10,
      "accessMin": 3,
      "accessMax": 8
    }
  }
}
```

| Key | Type | Default | Description |
|-----|------|---------|-------------|
| `maxCharsPerLevel` | `number[]` | `[200,2500,10000,25000,50000]` | Character limit per tree depth (L1..L5). Alternative: set `maxL1Chars` + `maxLnChars` and levels are interpolated linearly. |
| `maxDepth` | `number` | `5` | Max tree depth (1 = L1 only, 5 = full). |
| `defaultReadLimit` | `number` | `100` | Max entries returned by a default `read_memory()`. |
| `maxTitleChars` | `number` | `50` | Max characters for auto-extracted titles. |
| `checkpointInterval` | `number` | `20` | Messages between checkpoint reminders. Set 0 to disable. |
| `checkpointMode` | `"remind"` or `"auto"` | `"remind"` | `"remind"` = inject a save-reminder via `additionalContext`. `"auto"` = spawn a Haiku subagent that saves directly (no user interaction). |
| `recentOEntries` | `number` | `10` | Number of recent O-entries (session logs) injected at startup and on `load_project`. Set 0 to disable. |
| `contextTokenThreshold` | `number` | `100000` | Token threshold for context-clear recommendation. When cumulative hmem output exceeds this, the agent is told to flush + `/clear`. Set 0 to disable. |

**Bulk-read tuning** (`bulkReadV2`): controls which entries get expanded (all L2 children shown) in a default `read_memory()` call. Per prefix category, the top N newest + top M most-accessed entries are expanded. Favorites are always expanded.

| Key | Default | Description |
|-----|---------|-------------|
| `topAccessCount` | `3` | Fixed fallback: top-accessed entries to expand. |
| `topNewestCount` | `5` | Fixed fallback: newest entries to expand. |
| `topObsoleteCount` | `3` | Obsolete entries to keep visible. |
| `topSubnodeCount` | `3` | Entries with most sub-nodes to always expand. |
| `newestPercent` | `20` | Percentage-based selection (overrides `topNewestCount`). |
| `newestMin` / `newestMax` | `5` / `15` | Clamp for percentage-based newest selection. |
| `accessPercent` | `10` | Percentage-based selection (overrides `topAccessCount`). |
| `accessMin` / `accessMax` | `3` / `8` | Clamp for percentage-based access selection. |

---

## Manual Setup (Fallback)

Use these steps only if `hmem init` is not available (e.g., local clone without global install).

### Step 0 — Prerequisites

```bash
node --version    # must be >= 18
npm --version     # any recent version
```

`better-sqlite3` requires native build tools:

| OS | Install |
|----|---------|
| Linux (Debian/Ubuntu) | `sudo apt install python3 make g++` |
| Linux (Arch) | `sudo pacman -S python make gcc` |
| macOS | `xcode-select --install` |
| Windows | `npm install -g windows-build-tools` |

### Step 1 — Clone and Build

```bash
git clone https://github.com/Bumblebiber/its-over-9k.git
cd its-over-9k
npm install
npm run build
```

Verify: `dist/mcp-server.js` must exist after build.

### Step 2 — Create Memory Directory

```bash
mkdir -p ~/.hmem
```

The SQLite `.hmem` file is created automatically on first write.

### Step 3 — Configure MCP

Add hmem to your `.mcp.json` (create it at your project root if it does not exist). All paths must be absolute.

```json
{
  "mcpServers": {
    "hmem": {
      "type": "stdio",
      "command": "node",
      "args": ["/absolute/path/to/hmem/dist/mcp-server.js"],
      "env": {
        "HMEM_PATH": "/absolute/path/to/your/memory.hmem",
        "HMEM_AGENT_ROLE": "worker"
      }
    }
  }
}
```

| Variable | Description |
|----------|-------------|
| `HMEM_PATH` | Absolute path to your .hmem file (e.g. `~/.hmem/memory.hmem`) |
| `HMEM_AGENT_ROLE` | Permission level: `worker` / `al` / `pl` / `ceo` |

### Step 4 — Install Skill Files

Copy skill files to the global skills directory for your tool:

**Claude Code:**
```bash
mkdir -p ~/.claude/skills/o9k-read ~/.claude/skills/o9k-write ~/.claude/skills/save ~/.claude/skills/memory-curate
cp /path/to/hmem/skills/o9k-read/SKILL.md ~/.claude/skills/o9k-read/SKILL.md
cp /path/to/hmem/skills/o9k-write/SKILL.md ~/.claude/skills/o9k-write/SKILL.md
cp /path/to/hmem/skills/save/SKILL.md ~/.claude/skills/save/SKILL.md
cp /path/to/hmem/skills/memory-curate/SKILL.md ~/.claude/skills/memory-curate/SKILL.md
```

**Gemini CLI:**
```bash
mkdir -p ~/.gemini/skills/o9k-read ~/.gemini/skills/o9k-write ~/.gemini/skills/save ~/.gemini/skills/memory-curate
cp /path/to/hmem/skills/*/SKILL.md to corresponding ~/.gemini/skills/*/SKILL.md
```

### Step 5 — Verify

Fully restart your AI tool (exit and reopen — `/clear` is not enough). Then call:

```
read_memory()
```

Expected: `Memory is empty` (or your existing memories).

---

## Troubleshooting

| Symptom | Likely cause |
|---------|-------------|
| `HMEM_PATH not set` | Path missing or wrong env var name in `.mcp.json` |
| `No such tool: read_memory` | Tool not restarted after adding `.mcp.json` |
| `npm install` fails | Missing build tools (see Prerequisites above) |
| `read_memory` returns empty after writing | MCP server process is stale — restart tool |
| Hooks not firing | Check `~/.claude/settings.json` — hooks must be registered there |
| Checkpoint reminders not appearing | Verify `checkpointInterval > 0` in `hmem.config.json` |

---

## Quick Reference — After Setup

```
read_memory()                          # see all L1 memories
read_memory(id="L0001")               # drill into one entry
write_memory(prefix="L", content="Short title\n\nDetailed body text\n\tL2 sub-node")
search_memory(query="error node.js")  # search across all memories
```

Separate title from body with a blank line (hidden in listings, shown on drill-down). See `o9k-write` skill for details.

See `skills/o9k-read/SKILL.md` and `skills/o9k-write/SKILL.md` for full usage.

Related Skills

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