A Claude Code skill that turns every coding session into permanent, queryable knowledge.
Latest release: v3.2.0 · 2026-06-18 ·
supports Claude Code + Cursor (beta) · OKF v0.1 export —
/haze export --okf
haze-wiki is an LLM Wiki for Claude
Code (and Cursor). It auto-captures your conversations, records your
decisions, and grows a self-maintaining knowledge graph in your project
— so future sessions start with relevant context loaded instead of from
zero.
Inspired by Andrej Karpathy’s “LLM as Compiler” / Vannevar Bush’s
Memex: a layered vault of immutable raw sources (raw/) plus
an LLM-curated knowledge layer (wiki/), wired together by
lifecycle hooks.
OKF interoperability — export your vault as a Google Open Knowledge Format v0.1 bundle.
Google released Open Knowledge
Format (OKF) v0.1 (June 2026) — a vendor-neutral spec for
agent knowledge (Markdown + YAML frontmatter) that formalizes the same
LLM-wiki pattern haze-wiki already implements. v3.2.0 adds the first
outbound interoperability path so haze-wiki knowledge
can be shared with the Google Knowledge Catalog, external agents, and
other OKF consumers — without abandoning wikilinks,
hot.md, sessions/, or the ingest
pipeline.
/haze export --okf/haze export --okf [--out DIR] [--include-sessions] [--validate] [--dry-run]Converts a live vault into a conformant OKF v0.1 bundle. It is a one-way, read-only export — the authoring layer is never modified (verified byte-identical before/after).
| haze-wiki | OKF output |
|---|---|
wiki/concepts/foo.md |
concepts/foo.md
(type: concept→Concept,
poc→POC, …) |
[[slug]] / [[slug\|label]] |
[label](/concepts/slug.md) |
wiki/index.md |
index.md + okf_version: "0.1" |
wiki/log.md |
log.md (OKF §7 dated bullets) |
wiki/hot.md |
extensions/hot-cache.md (producer extension) |
wiki/sessions/*.md |
sessions/*.md (opt-in
--include-sessions) |
source / created / tags |
preserved as extension frontmatter keys |
| — | gap-analysis.md (auto haze↔︎OKF compatibility
report) |
--validate runs a permissive OKF
linter (hooks/lib/okf-lint.sh). Per OKF §9 it hard-fails
only on missing-frontmatter, empty-type, and
reserved-filename-misuse; broken links, unknown types, and
orphans are info-only (treated as growth signals, like
/haze lint).[[ "$x" == y ]]) is left untouched — it is not mistaken for
a wikilink.OKF is an exchange format, not a replacement.
haze-wiki stays the authoring layer (wikilinks,
hot.md, sessions, hooks, ingest, /haze lint);
the OKF bundle is a portable, Catalog-ready projection of
wiki/concepts/. Re-run the export to refresh.
The exporter ships as a compiled Rust binary
(haze-okf, source in okf-export/) for speed
and robust YAML/markdown handling, with a pure-shell
fallback baked into hooks/lib/okf-export.sh /
okf-lint.sh so curl | bash installs work with
zero toolchain. The wrapper prefers the binary when
found (via $HAZE_OKF_BIN, $PATH, or next to
the script); otherwise it runs the shell engine. Both produce conformant
bundles. Build the binary with cargo build --release in
okf-export/. (Prebuilt multi-platform binaries are a v3.3
item.)
Ported from the validated Google OKF study (POC-028 migrator, POC-024
linter). Validated on the reference vault: 135 concepts, 523
wikilinks converted, 42 broken (growth signals), 1074 sessions
with --include-sessions — linter result
CONFORMANT (0 errors, 0 warnings).
Reverse import (
/haze import --okf), Knowledge Catalog push, and cloud sync are deferred to v3.3+.
Entity metrics fix + proactive capture failure alerting.
The /haze metrics entity coverage was showing ~1% due to
the CamelCase regex matching Cursor tool names
(UpdateCurrentStep, StrReplace,
AwaitShell, etc.) and POC class names
(AbortController, AccessControlEnforcer, etc.)
instead of real tech entities.
Fix: Added two-tier filter to hooks/lib/metrics.sh: 1.
Tool stoplist: Cursor tool names (UpdateCurrentStep,
StrReplace, etc.) 2. Code suffix filter: Common class
suffixes (Controller, Manager, Handler, etc.)
Result: Entity coverage now reflects real tech entities (1% → 13%), and overall retention score improved (60% → 65%).
New hooks/lib/capture-alert.sh monitors transcript
capture health and alerts if no new transcripts appear for 24+ hours —
catching silent capture failures like the v3.0.2→v3.1.2 pipefail leak
before they go unnoticed for days.
session-start.sh hookbash hooks/lib/capture-alert.sh statusHAZE_ALERT_THRESHOLD_HOURS=12 (default: 24)When capture is broken, you’ll see a warning banner at session start with debugging guidance.
Critical fix — transcript capture was silently broken since
v3.0.2. The stop hook
(capture-transcript.sh) fired every turn but died with
FAILED_HOOK exit=2, so raw/transcripts/
stopped growing and /haze ingest --new never saw new
sessions — while track-code-change kept working, hiding the
outage.
Root cause: the hook sources
hooks/lib/session-registry.sh, which runs
set -euo pipefail. Because sourcing runs in the
same shell, pipefail leaks into the hook.
Combined with the hook’s own set -e, the v3.0.2
session-scoped line
existing=$(ls -1 raw/transcripts/*-${session_id}.jsonl | head -1)
aborts whenever the glob has no match (every new
session’s first turn): ls exits 2, and under
pipefail that 2 escapes the pipeline even
though head exits 0. The hook then died
before the cp, so the per-session file was
never created — failing identically on every subsequent turn,
forever.
Fix: set +o pipefail immediately after the lib-sourcing
block, restoring the default-bash pipeline semantics the script was
written for (also hardens the other ... | grep -v | ... and
git diff | head pipelines). One-line change to
templates/hooks/capture-transcript.sh; no schema or
behavior change otherwise.
Upgrade note: after
/haze update, restart your editor so the newstophook is loaded. Sessions started before the upgrade can be re-captured on their next turn.
Docs fix — stop the phantom “missing config.json”
warning. Since v2.7.2 the canonical config file is
haze-config.json (the hooks already prefer it, with a
legacy config.json fallback), but the command/skill/rule
docs still told the agent to read config.json. On a healthy
v2.7.2+ vault this produced a false “Missing config.json — pre-v2.7
layout” health warning and a bogus suggestion to run
init/migrate. All doc/template references now
point at haze-config.json, and /haze status
explicitly must NOT warn when haze-config.json is present.
No behavior or on-disk change — docs only
(commands/haze.md, rules/haze-wiki.mdc,
AGENTS.md, Claude SKILL.md,
README.md). The backward-compat fallback code is
unchanged.
Packaging fix: the Cursor installer now ships
hooks/lib/log-sink.sh. In v3.1.0 the sink library was
omitted from cursor-install.sh’s copy list, so the stop
hook’s optional sink flush had nothing to source. Re-run
cursor-install.sh --force to pick it up. No behavior change
when the sink is disabled (the default).
Optional ops-telemetry sink → EFK/Kibana, plus a co-located gateway service.
Ship the vault’s operational telemetry
(wiki/ops/*.jsonl) to a central Elasticsearch for
cross-machine observability — knowledge stays 100%
local. This is telemetry only: concepts/,
hot.md, index.md, sessions/ and
transcripts are never sent anywhere.
hooks/lib/log-sink.sh)current.jsonl incrementally via a byte cursor. With
delete_after_ship, fully-shipped rotated files are removed
locally (the gateway/ES becomes their home).HAZE_LOGSINK_KEY or
gitignored .secrets/logsink_key — never
from haze-config.json (that file isn’t gitignored).haze-config.json)"log_sink": { "enabled": false, "endpoint": "", "delete_after_ship": false }Disabled by default — zero behavior change unless you opt in.
haze-wiki-gateway
(new, in gateway/)POST /v1/ops,
/health, /ready, /metrics) that
accepts NDJSON ops from outside the cluster and writes them to
in-cluster Elasticsearch — so ES is never exposed and writes are
authenticated._id = sha1(line)), payload-capped,
rate-limited.gateway-v* tag (distinct from the
wiki’s Cloudflare deploy on main). Ships ES index template
(details as flattened) + ILM.Upgrade: Run cursor-install.sh --force.
The sink stays off until you set log_sink.enabled +
endpoint and provide a key.
Manifest hygiene — root-cause fixes for path drift, snapshot bloat, and a silent helper bug.
Subagents filled in {transcript_path} with whatever
prefix they were handed (absolute, haze-wiki/raw/...,
./raw/...), so the manifest carried the same logical file
under multiple keys — producing duplicate entries, gc
deletions that silently missed files, and lost
concepts_extracted_at stamps.
manifest_normalize_path() (and Redis/storage
equivalents) canonicalize every path to vault-relative
raw/transcripts/... at write time.manifest_dedupe() collapses path-variant duplicates
into one richest entry — summarized_at /
concepts_extracted_at / subsumed_by all
survive.subsumed_by pointers are normalized too.storage_gc normalizes subsumed paths before deleting
(so $root/$rel_file resolves), then runs normalize + dedupe
automatically — manifest hygiene on every run, no more orphaned
stamps.gc).session_id and overwrites in place. One canonical
file per session, zero subsumption.manifest_lock_update / manifest_lock_read
read $1 as the jq filter, but every caller passes the
filter last (after
--arg/--argjson). The helpers — including the
v2.7.8 subsumption dedup — were silently failing. Filter is now taken as
the last argument.Upgrade: Run cursor-install.sh --force,
then /haze gc once to normalize and dedupe an existing
manifest.
Metrics accuracy fix.
concepts/ directory (was incorrectly including session
cross-references)[[page#section]] → page)[[20260527-121740-bda686ad]])Before: wikilink coverage reported 100% even with broken links
After: accurately reflects actual concept page resolution rate
Upgrade: Run cursor-install.sh --force
to update hooks.
Rust CLI acceleration — 50x faster vault operations.
Introduces haze-cli, a native Rust binary that replaces
shell scripts for performance-critical operations.
| Command | Purpose | Speedup |
|---|---|---|
haze status |
Vault statistics | 50x |
haze manifest list/check/repair/prune/merge |
Manifest operations | 50x |
haze ingest scan/plan/run |
Parallel transcript processing | 20x |
haze metrics [--log\|--init] |
Retention score calculation | 30x |
haze sessions |
Redis-backed session registry | Native |
haze gc [--dry-run] |
Garbage collection | 20x |
haze archive create/list/restore |
Compression management | 20x |
Installation:
# From source
cargo install --git https://haze-gitlab.sssjiwjs.app/haze-public/haze-cli.git
# Or download pre-built binary
curl -fsSL https://haze-gitlab.sssjiwjs.app/haze-public/haze-cli/-/releases/v3.0.0/downloads/haze-cli-linux-x86_64 -o ~/.local/bin/haze
chmod +x ~/.local/bin/hazeUsage:
haze status # Auto-detects vault root
haze --root /path/to/vault status
haze manifest check --json # Machine-readable output
haze ingest run --parallel 4 # Parallel processingThe CLI complements (not replaces) the LLM-orchestrated
/haze commands. Use the CLI for: - Pre-flight checks before
ingest - Batch operations and automation - CI/CD integrity checks -
Monitoring dashboards
Binary size: 932KB (stripped, LTO-optimized)
Repo: https://haze-gitlab.sssjiwjs.app/haze-public/haze-cli
Storage management + hook throttling.
Addresses unbounded transcript growth (projected 9.5GB/year → bounded ~320MB).
throttle_delta_kb in haze-config.json (default:
10)/haze gc [--dry-run] — clean up subsumed
transcriptssubsumed_by in manifest/haze archive --older-than <days> — compress old
transcripts/haze metrics --storage — show storage breakdownhooks/lib/storage.sh — storage management libraryImpact: | Metric | v2.10.0 | v2.10.1 | |——–|———|———| | 1-year projection | 9.5 GB | ~320 MB | | Growth | Unbounded | Bounded | | Knowledge retention | 100% | ~90% |
Upgrade: Run cursor-install.sh --force.
Existing subsumed files will be cleaned on first
/haze gc.
Cross-session awareness + passive knowledge propagation.
Multiple wiki sessions can now see each other and share knowledge automatically.
stop hookhaze-wiki/hooks/lib/session-registry.shUsage:
source haze-wiki/hooks/lib/session-registry.sh
session_registry_list | jq '.' # List active sessions
session_registry_status # Show registry table<user_query> contenthaze-wiki/hooks/lib/extract-session-name.shUsage:
source haze-wiki/hooks/lib/extract-session-name.sh
extract_session_name "raw/transcripts/20260527-123456-abcd1234.jsonl"
# → "developer session"haze-wiki/hooks/wiki-sync-check.shHow it works: 1. Ingest writes
wiki/.sync-state.json with revision + changed concepts 2.
Other sessions check revision on their stop hook 3. If changed, inject
delta (hot.md + up to 2 concept pages) 4. Per-session cursor in
wiki/.sync-cursors/<session_id>
/haze sessions — list active sessions (alias for
registry status)stop hook now chains wiki-sync-check.sh
after capture-transcript.shpreCompact now uses
wiki-sync-check.sh --full for resyncUpgrade: Run cursor-install.sh --force
to get new libs and hooks.
Redis-backed manifest for parallel ingest.
Breaking change: Redis is required for parallel ingest. User provides Redis.
Requirements: - Redis server accessible -
redis-cli installed - Set HAZE_REDIS_HOST and
HAZE_REDIS_PORT (default: 127.0.0.1:6399)
Usage:
# In each subagent:
source haze-wiki/hooks/lib/manifest-redis.sh
manifest_redis_mark_summarized "raw/foo.jsonl" "wiki/sessions/foo.md"
# After all subagents complete:
manifest_redis_sync_to_file
manifest_redis_clearKey prefix:
haze:<workspace-md5-hash>:entries — multiple
workspaces can share one Redis.
Sequential fallback: Use
/haze ingest --summarize-only if Redis unavailable.
Manifest fragments for true parallel-safe ingest.
v2.7.9’s flock fix only addressed hook-level writes.
LLM-driven parallel ingest (multiple subagents running Phase 1
simultaneously) still had race conditions because: 1. LLM agents don’t
auto-use bash helpers — they read/write JSON directly 2. Subagents may
run in isolated sandboxes without access to the same filesystem
Fix: New manifest fragments
pattern: - Each parallel agent writes to its own fragment file:
wiki/.manifest.d/<agent-id>.json - No conflicts —
each agent has exclusive access to its fragment - After parallel work
completes, parent runs /haze manifest merge to atomically
combine all fragments
New files: -
haze-wiki/hooks/lib/manifest-fragments.sh — fragment
helpers
New commands: - /haze manifest merge —
merge all pending fragments into main manifest -
/haze manifest status — show pending fragments without
merging
Usage for parallel ingest:
# In each subagent (unique AGENT_ID per agent):
source haze-wiki/hooks/lib/manifest-fragments.sh
manifest_fragment_mark_summarized "$AGENT_ID" "raw/transcripts/foo.jsonl" "wiki/sessions/foo.md"
# After ALL subagents complete, in parent:
/haze manifest mergeFallback: If subagents can’t access the workspace
filesystem (Cursor sandbox issue), use sequential
/haze ingest --summarize-only instead.
Manifest race condition fix for multi-agent Cursor sessions.
When multiple parallel agents (e.g., shadow-clone workers, or
multiple Cursor agent windows) write to .manifest.json
simultaneously, a race condition causes entries to be lost — the last
writer wins, overwriting other agents’ changes. This was critical for
parallel ingest workflows.
Fix: Added flock-based file locking for
all manifest writes: - New helper:
haze-wiki/hooks/lib/manifest-lock.sh with atomic
operations: - manifest_lock_update <jq-filter> —
exclusive lock for writes -
manifest_lock_read <jq-filter> — shared lock for
reads - manifest_add_processed,
manifest_mark_subsumed, manifest_update_entry
— high-level helpers - Updated integrity.sh’s
record_raw_hash to use flock when available -
Cursor commands/haze.md updated with parallel execution
warnings and dedup instructions
Fallback behavior: On systems without
flock (some macOS setups), falls back to legacy non-atomic
writes with a warning. Install coreutils via Homebrew for
full support.
Breaking change: None. Existing vaults work unchanged. New installs get the lock helper automatically.
Upgrade path: Run
cursor-install.sh --force to get the new
manifest-lock.sh helper, or manually copy
templates/hooks/lib/manifest-lock.sh to your vault.
Bug 8 — /haze ingest --new Phase 1 dedup. The Stop hook
fires per agent-turn under both Claude Code and Cursor, so a single chat
session produces N nested-superset transcript snapshots
(20260526-181006-a78bffed.jsonl is a strict superset of
20260526-180916-a78bffed.jsonl, both same session).
Pre-v2.7.8, Phase 1 would summarize each snapshot separately — wasting
~$0.50-2 per redundant summary, ~$3-15 per long session.
Fixed by adding a dedup pre-pass (Step 2a) in the
/haze ingest --new spec: - Group pending
needs_summary transcripts by the 8-char
session_id suffix in the filename - For each group, keep
only the largest snapshot for Phase 1 - Mark the rest
in the manifest with subsumed_by: <largest-path> +
subsumed_at: <iso8601> - Smaller snapshots stay on
disk (no deletion); they’re just skipped by future ingest runs
Manifest schema gains a 3rd entry shape (subsumed). Backward-compat:
pre-v2.7.8 manifests without subsumed_by work fine — dedup
runs on next ingest and adds them as it groups.
Optional follow-up (not in v2.7.8): a
/haze prune-transcripts sub-command could later rm subsumed
files + their raw_integrity entries. Deferred until disk
hygiene actually becomes a concern.
No template, hook script, or config changes — entirely a SKILL.md spec text addition.
Bug 9 — /haze shadow-clone Step 3 (Harvest) wasn’t
recording sha256 for harvested clone outputs, leaving
raw/shadow-<id>/* files unrecorded in
.manifest.json’s raw_integrity map.
/haze verify-raw would flag them as NEW (unrecorded). Stop
hook had this fix in v2.7.0; shadow-clone harvest missed the
cherry-pick.
Fixed by re-shaping Step 3’s bash loop to cp one file at
a time and call record_raw_hash $dest after each copy.
Sources haze-wiki/hooks/lib/integrity.sh first; falls back
gracefully if the helper is missing (legacy vaults).
Validated against the 2026-05-26 evening shadow-clone E2E run (clone
id 23819e8c, 2 harvested files) — pre-v2.7.7 left both
files unhashed.
/haze shadow-clone Step 5 (Auto-Ingest) wording
strengthened. Pre-v2.7.6 the step read as descriptive (“Automatically
process harvested files”) — an LLM running shadow-clone could plausibly
stop after the harvest and tell the user to run
/haze ingest --new themselves. Now reworded as imperative
with explicit “MANDATORY — do NOT skip” + “do not delegate this back to
the user” instructions. Also lays out two implementation paths (inline
synthesis for small batches, delegate to --new for larger
ones).
No functional code change — templates/hooks/* untouched.
The change is entirely in the LLM-orchestrated spec text the agent reads
when dispatching /haze shadow-clone.
Cleanup: removed a stale “/tmp/shadow-{id}/” path claim from
wiki/concepts/shadow-clone-pattern.md documentation (paths
were already correct in SKILL.md as of v2.7.5; the concept page had
propagated an older note).
5th bug surfaced during v2.7.4 live re-validation in Cursor — POC
paths whose name contains “test” (e.g. poc/cursor-test/,
poc/auth-test-harness/) were having their
WIKI_SUGGEST suppressed by the *test* glob
meant for test fixtures. Result: code_change ops fired correctly but no
[[poc-<name>]] suggestion ever printed for these
POCs.
Fix: POC paths now bypass the test/config
suppression entirely. *test* / *spec* /
*.config.* / *.json / *.lock
suppression still applies to non-POC paths. Effect:
| Path | v2.7.4 | v2.7.5 |
|---|---|---|
poc/cursor-test/balance.go |
(suppressed by *test*) |
[[poc-cursor-test]] |
poc/foo/bar.go |
[[poc-foo]] |
[[poc-foo]] (unchanged) |
src/foo_test.go |
(suppressed) | (still suppressed — not a POC path) |
cmd/main.go |
[[main]] |
[[main]] (unchanged) |
Patched in both templates/hooks/track-code-change.sh and
.claude/skills/haze/SKILL.md.
Cursor live-E2E follow-up — 4 bugs surfaced in v2.7.3 during a full validation pass against Cursor v3.5.33:
*.md exclusion in
track-code-change.sh. Pre-v2.5 it skipped all markdown to
avoid hook recursion; the fix shipped to SKILL.md but regressed into the
release templates/hooks/. Silently hid every markdown edit
under Cursor (the canonical workflow for the wiki itself!).capture-transcript.sh. The Cursor JSONL schema embeds
tool_use items inside .message.content[];
Claude Code emits them as their own top-level lines. Pre-fix, Cursor
session summaries had an empty ## Tools Used block. Now
tries both shapes; works on both.track-code-change.sh (release-side; already in SKILL.md).
Edits under poc/<name>/ now suggest
[[poc-<name>]] instead of basename-derived noise like
[[CLAUDE]] / [[README]] /
[[index]].sessionStart does NOT fire under Cursor
v3.5.x — neither on workspace open nor on agent-chat start.
Documented as a known limitation in the Multi-Editor section;
afterFileEdit, stop, and
preCompact all fire correctly.Install banner shows version — both
install.sh and cursor-install.sh now print a
header at the top of the run with the version they’re about to install.
Sourced from a single VERSION file at the repo root, so
future bumps are one-line changes. Sample output:
╔══════════════════════════════════════════════════╗
║ haze-wiki Cursor installer — v2.7.3
║ Target: /root/devops/temp/poc-go-server
╚══════════════════════════════════════════════════╝config.json →
haze-config.json when running
cursor-install.sh --force. Pre-v2.6 vaults used
haze-wiki/config.json; v2.6+ canonical is
haze-config.json. The installer now detects, renames
(backing the legacy up as config.json.legacy-bak), then
jq-merges with current defaults so existing values are preserved. No
more “no config.json — pre-v2.7 layout” warning after running the
installer.afterFileEdit works — fixed
payload-shape mismatch. Cursor sends file_path at top
level; Claude Code uses .tool_input.file_path.
track-code-change.sh now reads
.tool_input.file_path // .file_path to handle both. Settles
task #12 from the v2.5 Cursor live test.haze-wiki/.tmp/ convention —
workspace-scoped debug artifacts and ad-hoc temp state go here instead
of system /tmp/. Survives reboots, gitignored, takes itself
out on rm -rf haze-wiki/. Install-time scratch (git clones
during install) still uses system /tmp/./haze status shows version —
=== Wiki Status (v2.7.1) === header read from
haze-wiki/haze-config.json. Plus health warnings for stale
hot.md, pending raw/ files, pre-v2.7 layout, and recent FAILED_HOOK
events./haze verify-raw — new sub-command
that detects tampering of files under haze-wiki/raw/. Each
captured transcript now gets a sha256 stamp; verify-raw
flags MODIFIED / NEW / MISSING files. Use --bootstrap to
register hashes for files captured before v2.7.START / OK /
FAILED_HOOK exit=<code> to
haze-wiki/log.md. Silent timeouts (5s for PostToolUse, 10s
for Stop) are no longer invisible — they leave START with
no matching terminal event."async_stop_hook": true in
haze-wiki/haze-config.json to fork the transcript capture
into background so session-end doesn’t block. Default off; tradeoff is
the orphaned-child risk.install.sh before running.
Tag annotations include the canonical hashes./haze ingest — Phase 1
summarizes each transcript to wiki/sessions/<id>.md
(5–10 KB structured), Phase 2 extracts concepts from those summaries
instead of raw transcripts. Drops Phase 2 token cost ~10× and improves
concept quality./haze suggest — new sub-command for
concept discovery. Frequency + cross-source analysis proposes candidates
with NEW / STALE / EXISTING buckets. Always read-only until you
approve.=== HAZE PRELOAD === block listing exactly which pages got
injected, so the agent always knows what context it has vs needs to
/haze lookup.cursor-install.sh (no ~/.claude/ writes);
hooks.json requires "version": 1
(auto-handled). See Install.haze-wiki/log.md size-rotating (1 MB default, configurable
via debug_log_max_mb).Full release history below · Install instructions
A typical week with Claude Code: 30 sessions, dozens of decisions, three deep research dives, hundreds of file edits. After two weeks you’ve forgotten 80% of it. The next session starts from zero context — you re-explain the architecture, re-derive the same trade-off analysis, re-paste the same snippets.
haze-wiki makes the past stick. Every
session is auto-captured. The wiki self-maintains. Future sessions load
the relevant slice of past knowledge automatically — without you
remembering to do anything.
SESSION 1 → captured → ingested → wiki/ pages
│
SESSION 2 ← hot.md context ← index.md ─┘
│
produces new knowledge → captured → ingested → wiki/ pages
│
SESSION 3 ← compounds ← compounds ←────────────────────┘
Knowledge compounds. Sessions get smarter.
Here is what haze-wiki does around a single Claude Code
session, after you’ve run /haze init once:
SessionStart hook fireswiki/hot.md (recent context cache) and injects it
into Claude’s contextwiki/index.md (catalog of all wiki pages) so
Claude knows what’s already filedraw/ that haven’t been ingested
yet (so you can /haze ingest --new if you want)PostToolUse hook fires on every file
editEdit / Write tool call to
wiki/code-journal.mdPostCompact hook fireshot.md +
index.md so the post-compaction context still has the wiki
at handStop hook firesraw/transcripts/<timestamp>.jsonlhot.md if the wiki changed
this session/haze ingestraw/ (transcripts, articles,
anything you’ve dropped in)wiki/concepts/: adds new ones,
cross-links existing ones, deduplicateswiki/log.mdwiki/index.mdAfter a few cycles you have a knowledge graph that: - Loads
automatically each session - Surfaces past decisions when relevant via
/haze lookup - Cross-links concepts across projects (via
closure architecture — see below)
| Hook | Trigger | What it does | Configurable? |
|---|---|---|---|
SessionStart |
Session opens (startup or resume) | Inject hot.md + index.md into context;
report pending raw/ files |
matcher: startup\|resume |
PostToolUse |
Edit or Write tool fires |
Append entry to wiki/code-journal.md |
matcher: Edit\|Write, 5s timeout |
PostCompact |
Conversation auto-summarized | Re-inject hot.md + first 50 lines of
index.md so wiki stays in view |
Inline command |
Stop |
Session ends or is interrupted | Save transcript to raw/transcripts/; print
update-hot.md reminder |
10s timeout |
All four are configured in .claude/settings.json as
type: command hooks. They are non-blocking — a hook failure
surfaces as a soft error in Claude Code but never aborts the
session.
The hook scripts live under haze-wiki/hooks/ and use
absolute paths (set up by /haze init), so they work
regardless of your current working directory.
After /haze init, you no longer have to remember
to:
Stop hook captures every
transcriptSessionStart hook loads
it/haze ingestPostToolUse logs
themPostCompact re-injects
the wikiYou still drive:
/haze ingest (after meaningful sessions, or
batch via /haze ingest --new)raw/ (articles, PDFs,
transcripts, screenshots)/haze shadow-cloneVaults can link upward. Knowledge flows from leaves to root:
~/haze-wiki/ ← global vault (top)
│
├── ~/team-vault/ ← team vault, linked to global
│ │
│ ├── ~/proj-a/ ← project leaf
│ └── ~/proj-b/ ← project leaf
│
└── ~/personal-vault/ ← linked to global directly
Set up with --parent flags:
# Global vault (root of the closure)
cd ~/haze-wiki && /haze init
# Team vault (links to global)
cd ~/team-vault && /haze init --parent ~/haze-wiki
# Project (links to team)
cd ~/my-project && /haze init --parent ~/team-vault/haze push <concept> propagates a concept page
from leaf → team → global. The global vault becomes a knowledge graph
spanning all your projects — Karpathy-style “LLM as Compiler” applied to
your entire workflow.
Reference implementation: a closure-vault PoC with 119 leaf workspaces (60 research + 59 Go services) synthesized into 17 hubs + 6 executive concept pages.
For big-picture investigations where one agent isn’t enough:
/haze shadow-clone "compare cursor vs claude code hook systems"
This spawns 3–8 parallel research agents (a 影分身 / shadow-clone),
each tackling a sub-topic. Each writes to
raw/shadow-<topic>-<date>/ as an independent
markdown file. After all clones return, you can
/haze ingest to synthesize them into linked concept
pages.
A real run on “the Cursor port story” (5 agents, ~$2 of tokens):
Reads like a research team. Ships in 5 minutes instead of 5 days.
| Command | Purpose | When to use |
|---|---|---|
/haze init |
Scaffold wiki + install hooks | One-time per project |
/haze init --parent <path> |
Link to an upstream vault | Closure architecture |
/haze init --cursor |
Force Cursor port files | If .cursor/ not yet present |
/haze init --no-cursor |
Skip Cursor port files | If you only want Claude Code |
/haze status |
Vault stats — page count, pending files | Daily sanity check |
/haze check |
Verify hooks + config integrity | Debug |
/haze ingest [file] |
Process a single source | Quick one-off ingests |
/haze ingest --new |
Batch ingest (two-phase, v2.6+: summarize → synthesize) | End-of-day workflow |
/haze ingest --summarize-only |
Phase 1 only — transcripts → wiki/sessions/
summaries |
Batch process large backlog |
/haze ingest --synthesize-only |
Phase 2 only — summaries → concepts | Re-extract without re-summarizing |
/haze suggest [--top N] |
Propose concept candidates from pending material | After ingest or before research |
/haze suggest --refresh |
Show stale concepts that have new source material | Weekly housekeeping |
/haze ingest --poc |
Synthesize concept pages from poc/*/ folders |
For workspaces with PoCs |
/haze ingest --poc --dry-run |
Preview ingest, no writes, token estimate | Cost check first |
/haze ingest --poc <name> |
Re-index one POC, force overwrite | After PoC evolved |
/haze lookup <topic> |
Search wiki + inject relevant pages | Bring past context into chat |
/haze push [file] |
Send concept page upward to parent vault | Manual closure sync |
/haze config |
Show/edit vault config | Tweak ingest behaviour |
/haze shadow-clone <topic> |
Spawn N parallel research agents | Big investigations |
/haze update |
Re-run installer to pull latest skill version | Stay current |
/haze reinit |
Re-run init without overwriting wiki content | After skill updates |
/haze reset |
Tear down + reinstall (destructive on hooks) | Last resort |
/haze init auto-detects Cursor (looks for
.cursor/) and writes a parallel set of port files so the
same wiki works from either editor:
AGENTS.md (the cross-editor standard) + a
CLAUDE.md → AGENTS.md symlink.cursor/commands/haze.md — $ARGUMENTS
dispatch (stable in Cursor v1.6+).cursor/rules/haze-wiki.mdc — alwaysApply
rule with @file injection of hot.md +
index.md.cursor/hooks.json — sessionStart,
stop, afterFileEdit, preCompact
(Cursor v1.7+).cursor/hooks/*.sh — symlinks back to
haze-wiki/hooks/*.sh (one script set, two consumers)⚠ Caveats (validated against Cursor v3.5.33 in live E2E, 2026-05-26):
sessionStart hook does NOT fire under Cursor
v3.5.x — neither on workspace open nor on agent-chat start.
afterFileEdit, stop, and
preCompact work correctly. Net effect: the preload header
and pending-ingest reminders that work under Claude Code don’t surface
automatically in Cursor sessions. Workaround: run
/haze status manually inside the Cursor chat to get the
same data on demand..md corruption bug (forum
#158747, fix targeted v3.3) — should be resolved in 3.3+; verified
non-issue on 3.5.33 in the E2E.docs/cursor-support.md in the dev repo for the
running list of behaviour findings.To skip Cursor entirely: /haze init --no-cursor.
/haze init)your-project/
├── .claude/
│ └── settings.json ← hooks wired here, absolute paths
└── haze-wiki/
├── haze-config.json ← per-vault config (parent links, etc.)
├── hooks/
│ ├── lib/ ← shared helpers (cwd resolution, etc.)
│ ├── lib/debug-log.sh ← rotating debug logger (sourced by hooks)
│ ├── session-start.sh ← SessionStart hook script
│ ├── track-code-change.sh ← PostToolUse hook script
│ └── capture-transcript.sh ← Stop hook script
├── log.md ← rotating DEBUG log (hook/skill behaviour, 1MB default)
├── raw/ ← IMMUTABLE source layer
│ ├── transcripts/ ← auto-captured conversations
│ ├── shadow-*/ ← multi-agent research outputs
│ └── *.md *.pdf ← user-dropped sources
└── wiki/ ← LLM-MAINTAINED knowledge layer
├── hot.md ← recent context (auto-loaded each session)
├── index.md ← catalog of all pages
├── log.md ← append-only USER-FACING activity log
├── code-journal.md ← code-edit log (PostToolUse output)
├── concepts/ ← one file per concept
└── sessions/ ← transcript summaries (post-ingest)
Two logs, distinct purposes: -
haze-wiki/log.md— rotating debug log for hook + skill behaviour. Default 1 MB cap, configurable viahaze-config.json’sdebug_log_max_mb(e.g. set to10for a 10 MB cap). When oversize, the oldest ~50% is pruned in place. For troubleshooting. -haze-wiki/wiki/log.md— append-only user-facing activity log. Format## [YYYY-MM-DD] <op> | <summary>. Never rotated. For history and audit.
Layer rules:
raw/ is immutable. You add files; the
wiki layer reads them. Nothing is mutated.wiki/ is LLM-maintained.
/haze ingest creates, updates, and cross-links pages..claude/settings.json is wired with absolute paths so
hooks work from any cwd.Two installers — pick by editor:
curl -fsSL https://haze-gitlab.sssjiwjs.app/haze-public/haze-wiki/-/raw/main/install.sh | bashWrites the skill to ~/.claude/skills/haze/
(machine-wide, one-time). Then cd into a project and run
/haze init from inside Claude Code to scaffold the
vault.
cd your-project
curl -fsSL https://haze-gitlab.sssjiwjs.app/haze-public/haze-wiki/-/raw/main/cursor-install.sh | bashLays down .cursor/, AGENTS.md,
CLAUDE.md → AGENTS.md symlink, and the
haze-wiki/ scaffold in $(pwd). Nothing touches
~/.claude/. Per-project install — re-run in each workspace
you want to use it in.
⚠ Cursor v3.x has a confirmed
.mdcorruption bug (forum #158747, fix targeted v3.3). Use Cursor Nightly until v3.3 ships.
Run cursor-install.sh first (lays down the workspace
files + CLAUDE.md symlink), then run
install.sh to also get the Claude Code skill globally. The
two installers don’t conflict.
curl ... | bash is the friction-free default but doesn’t
let you inspect what you’re about to run. To verify first:
# 1. Download the installer
curl -fsSL https://haze-gitlab.sssjiwjs.app/haze-public/haze-wiki/-/raw/main/install.sh -o /tmp/haze-install.sh
# 2. Compute its sha256
shasum -a 256 /tmp/haze-install.sh
# or: sha256sum /tmp/haze-install.sh
# 3. Compare against the canonical hash published in the v2.7.0 (or current) tag annotation:
# git -c http.proxy= ls-remote --tags https://haze-gitlab.sssjiwjs.app/haze-public/haze-wiki.git
# Or visit https://haze-gitlab.sssjiwjs.app/haze-public/haze-wiki/-/tags/v2.7.0
# The tag message contains "install.sh sha256: <hash>".
# 4. If the hash matches, run it:
bash /tmp/haze-install.shSame flow for cursor-install.sh.
Limitations (be honest): if
haze-gitlab.sssjiwjs.app is compromised, the published hash
can be rewritten too — verify-then-install protects against
opportunistic mid-transit tampering, not a full server compromise. For
higher assurance, mirror the repo to a second host and cross-check.
git clone https://haze-gitlab.sssjiwjs.app/haze-public/haze-wiki.git
cp -r haze-wiki/.claude/skills/haze ~/.claude/skills/ # Claude Code skill
# or: cp -r haze-wiki/templates/cursor/ /target/.cursor/ # Cursor port files
rm -rf haze-wikiRe-run whichever install one-liner you used — both installers replace
the existing files with the latest from main:
# Claude Code skill
curl -fsSL https://haze-gitlab.sssjiwjs.app/haze-public/haze-wiki/-/raw/main/install.sh | bash
# Cursor workspace (pass --force to overwrite existing haze-wiki/)
curl -fsSL https://haze-gitlab.sssjiwjs.app/haze-public/haze-wiki/-/raw/main/cursor-install.sh | bash -s -- --forceInside Claude Code: /haze update runs the global skill
installer.
cd your-project
claude
# Inside Claude Code:
/haze init # scaffold + install hooks
/haze status # confirm everything's wiredNow drop sources into haze-wiki/raw/ (articles, PDFs,
transcripts) and run:
/haze ingest --new
After 3–4 sessions you’ll have a self-growing knowledge graph that survives every restart.
jq — used by hooks for transcript
parsingbash — POSIX-ish, hooks tested on
macOS + LinuxVERSION file at repo root. Both installers read it
and display a versioned banner at start. cursor-install.sh
uses it as the default version field in fresh configs.
Future releases bump one file.cursor-install.sh --force now auto-migrates legacy
haze-wiki/config.json →
haze-wiki/haze-config.json. Existing values preserved via
jq merge; legacy backed up as config.json.legacy-bak.debug-log.sh,
capture-transcript.sh) try both filenames so pre-v2.6
vaults still work without reinstalling.2.7.2 in fresh installs.afterFileEdit works —
track-code-change.sh now reads
.tool_input.file_path // .file_path so the hook fires
correctly under both Claude Code (.tool_input.file_path)
and Cursor (top-level .file_path). Settles task #12 from
the v2.5 live test; finding: payload-shape mismatch, not Cursor missing
the event.haze-wiki/.tmp/ for workspace-scoped temp
artifacts (gitignored). System /tmp/ reserved for
install-time scratch only./haze status shows version (from
haze-config.json) + new health warnings (stale hot.md,
pending raw/ files, pre-v2.7 layout, recent FAILED_HOOK events)..md corruption bug (forum
#158747) appears resolved in v3.3+. Live edit + frontmatter integrity
confirmed on the test workspace./haze verify-raw [--bootstrap] [--diff <file>] —
sha256-based tamper detection for haze-wiki/raw/. New
lib/integrity.sh library; manifest schema extended with
raw_integrity object. Detection only (honest about the
LLM-bypass case — pair with git for true tamper-prevention).START
/ OK / FAILED_HOOK exit=<code> via the
existing debug-log.sh, so silent timeouts (5s PostToolUse, 10s Stop) now
leave a trail. /haze status can surface the count."async_stop_hook": true in
config) — capture-transcript.sh re-forks itself in
background so session-end doesn’t block. Default off; orphan-child
tradeoff.install.sh and
cursor-install.sh./haze ingest --new (Phase 1: summarize
transcripts → wiki/sessions/; Phase 2: extract concepts
from summaries). Drops Phase 2 token cost ~10×.--summarize-only and
--synthesize-only for either phase in isolation./haze suggest [--top N] [--refresh] sub-command for
concept discovery and stale-concept detection.session-start hook listing which wiki
pages got injected.summarized_at +
concepts_extracted_at timestamps; pre-v2.6 entries treated
as fully processed (no upgrade re-work).cursor-install.sh — per-workspace Cursor installer, no
global ~/.claude/ writes.AGENTS.md,
.cursor/commands/haze.md,
.cursor/rules/haze-wiki.mdc,
.cursor/hooks.json.hooks.json requires top-level
"version": 1 (caught in Cursor 3.x live test).haze-wiki/log.md — rotating debug log for hook +
skill behaviour (1 MB default).wiki/+raw/+.claude/hooks/
consolidated under haze-wiki/./haze migrate for v1→v2 upgrades..claude/settings.json so hooks
survive cwd changes.MIT
haze (霞) — drifting cloud, ephemeral but persistent. This tool fixes the ephemeral part.