# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## What this repository is `cc-os` is a **design + implementation repository** — it captures the design of a **personal, cross-project memory system for Claude Code** (for a multi-client freelancer) plus the research that informs it. The global memory plugin is now partially implemented; markdown specs, ADRs, and the build plan remain the source of truth for what is being built and what remains. Everything is markdown-as-truth. When asked to "build," work from the staged tasks in `docs/memory-system/04-build-plan.md`, not ad hoc. ## Directory layout Numbered files within a directory are not a required reading order — read the one whose topic you need. - **`docs/memory-system/`** — the design of the memory system itself. Go here to understand or change *what is being built*. `02-system-design.md` is the architecture, `03-architecture- decisions.md` is the ADR log (each decision + what was rejected/deferred and why), `04-build-plan.md` is the build outline, `06-graphify-evaluation.md` justifies the Graphify pivot. Read the specific file relevant to your task; read the whole set only when reworking the design. - **`docs/graphify/`** — a verified handbook for the Graphify knowledge-graph tool (the chosen knowledge-layer engine). Go here when working with Graphify commands/behavior. Skim `00-README.md` for the model, keep `09-best-practices-checklist.md` open while actually running it. Claims are provenance-tagged (`[github]` trustworthy; `[interview]` / `[unverified claim]` not). - **`graphify-interview`, `memory-systems-compared060326`** (repo root) — raw source transcripts (marketing / video). Only open these to trace where a claim came from; treat as *intent*, not *fact* — they were already corrected against primary sources in `docs/`. - **`openspec/`** — spec-driven change management (see workflow below). `changes/` holds live changes, `changes/archive/` completed ones, `specs/` stable specs. - **`.claude/`, `.codex/`, `.pi/`** — **identical** copies of the OpenSpec skills for three AI assistants. Only open when changing a skill — and mirror any change across all three. ## The current design in one paragraph This is a **work in progress**, not a frozen spec. The paragraph below is the current approach; treat it as the default you operate from, but **whenever a conversation with the user changes the design, update this paragraph (and the relevant `docs/memory-system/` files + an ADR) to match.** Keep it accurate, don't preserve it for its own sake. Two memory types kept as **separate systems**: **episodic** ("what happened, when") handled by **memsearch** (Milvus Lite, embedded), and **semantic/knowledge** ("how do we…") handled by the existing **`~/Documents/SecondBrain` Obsidian vault** as the single source of truth. Notes keep `summary` + six flat, parallel namespaced facets (`type/`/`client/`/`project/`/`domain/`/`tool/`/`convention/`) plus `scope/` as metadata; hierarchy and relationships are expressed via hub notes (`type/hub`), wikilinks, and Graphify graph edges — not nested tag paths. The vault is queried via a **Graphify knowledge graph** (local Ollama SLM for doc extraction, free tree-sitter AST for code). Retrieval is hook-injected + on-demand so project repos stay thin; freshness is lazy (write-time hook + SessionStart reconcile, no daemon/cron); the vault syncs to a VPS while indexes stay disposable and rebuildable. Ships as a global Claude Code plugin (`os-vault`) with skills. **Recent pivot (2026-06-03):** Graphify **replaces** the originally-planned Ruby/SQLite tag-index CLI and also covers the deferred QMD semantic layer. `04-build-plan.md` and `06-graphify-evaluation.md` reflect this; if an older doc still describes the Ruby CLI, defer to those two and fix the stale doc. **Decisions locked (2026-06-04):** Six-facet tag taxonomy + `scope/` (ADR-011); reuse `~/Documents/SecondBrain` vault rather than creating a new one (ADR-012); build-first / migrate-incrementally — build full system against a fixture set first, defer bulk vault migration to last, onboard projects one at a time (ADR-013). **Empirical finding locked (2026-06-05):** Graphify is a structure extractor, not a topic clusterer — no emergent hub nodes appear even at `--mode deep`; hub notes + wikilinks must be author-provided during migration (not deferred). Migration scaffolding is now a first-class deliverable. Open question: do facet tags create graph edges? (ADR-014; findings: `docs/memory-system/07-graph-connectivity-findings.md`). **Implementation status (2026-06-09):** The global Claude Code plugin is live (`~/.claude/plugins/os-vault/`). Steps 1, 2a, 2b, 3, and 6 of the build plan are complete (including the `onboard-project` skill, previously TODO under Step 6/Part D). Step 1 completed 2026-06-09: vault-conventions.md exists, all 6 fixture notes seeded, and 14 Graphify handbook + memory-system design notes migrated to the vault as migration scaffolding. Step 4 (memsearch) completed 2026-06-09: plugin installed via marketplace, MEMSEARCH_DIR set global (~/.memsearch), Stop hook verified producing daily memory files, search confirmed working. Step 5a (memsearch episodic git sync) completed 2026-06-09: dedicated private Forgejo repo (`forgejo.swansoncloud.com/jared/memsearch`), whitelist `.gitignore` (memory/*.md only), auto-commit+push via cc-os `session-end.sh` hook (ADR-015; relocated to `memsearch_sync.py` by ADR-016, 2026-06-12). Step 5b (Obsidian vault → VPS sync) remains. See `docs/memory-system/04-build-plan.md` for full step status. **Decision (2026-06-09):** Single global memsearch store for ALL clients — cross-client commingling is the accepted, intended design (ADR-015 resolved). One private Forgejo repo (`forgejo.swansoncloud.com/jared/memsearch`), not per-client repos. Forward direction: minimize/eliminate dedicated per-client working directories; work projects locally or use a single general `clients/` dir for non-local client work — memory is captured globally regardless of cwd. No `clients/` directory structure designed yet; open item. **Implementation status (2026-06-12):** os-vault plugin source moved into git at `cc-os/plugins/os-vault/` and bash hooks ported to Python (deep-module architecture: shared `config.py`, `hook_io.py`, `session_state.py`; thin entry-point scripts). Cutover via symlink `~/.claude/plugins/os-vault → cc-os/plugins/os-vault/` and settings.json hook rewrite. memsearch sync split into dedicated `memsearch_sync.py` SessionEnd hook (relocation of ADR-015 behavior, not reversal). Fresh-session test passed 2026-06-12. See ADR-016. **Implementation status (2026-06-15):** Step 5b done and automated — vault (`~/Documents/SecondBrain`) initialized as git repo, pushed to private Forgejo (`ssh://git@forgejo.swansoncloud.com:2222/jared/SecondBrain.git`); 52 files, git chosen over Syncthing. Auto-commit+push wired via `vault_sync.py` SessionEnd hook (third SessionEnd hook, runs after `session_end.py` so the daily journal note is included; push-only — SessionStart pull is an optional future item for multi-machine). Step 2e pilot done — llf-schema (`/home/jared/dev/llf-schema`, PHP 8.2 WordPress plugin) onboarded via `/os-vault:onboard-project` skill: 605 nodes / 930 edges / 52 communities; Ollama doc pass lossy on WordPress docs but AST pass solid. Step 2d closed — live vault `graphify-out/` is the baseline; fixture-only build superseded. **Implementation status (2026-06-17):** `/os-vault:onboard-project` skill now uses assessment-first onboarding: surveys the repo structure, classifies exclude candidates by TYPE (11 categories: fetched deps, build output, caches, VCS internals, editor/AI-tooling dirs, lockfiles, coverage/logs, bulk data, binaries, secrets, graphify-out/ — illustrative names, not fixed templates), generates a per-project `.graphifyignore`, confirms with the user, then extracts the graph using `qwen25-coder-7b-16k` (config.yaml `ollama_model`; 16k-context build of qwen2.5-coder:7b — larger context window cuts chunk count per doc, the main speed lever). Fixes issue where repos with large dependency trees routed non-code files through the Ollama doc pass (see ADR-017). **Implementation status (2026-06-30):** Phase 1 of the SecondBrain Content Plan complete (`docs/memory-system/09-sb-content-plan.md`, issues #1–#6). `~/Documents/SecondBrain/vault-conventions.md` reconciled to a single authoritative typed frontmatter schema (removed the contradictory block; canonical filenames are slug-only, `source:` is a frontmatter field not a tag, `scope` is a field not a tag). New `/os-vault:design-template` skill added (`cc-os/plugins/os-vault/skills/design-template/SKILL.md`) — routes between template-design (4-step process + injection-economics filter) and new-type creation (9-step lifecycle). Three vault note templates created in `~/Documents/SecondBrain/_templates/` (`howto.md`, `convention.md`, `reference.md`; `reference` carries a four-subtype variant selector — pattern/framework, api-integration, role-definitions, design-rules), each dogfooded against a real note. Four proof-of-concept vault notes patched (cookbook subtype → pattern/framework, glossary de-duped to a wikilink, design-mode scope → project, tags + `last_reviewed` added). Phase 2 (issue #7) remains open as the steady-state migration/onboarding epic (no code). See `docs/memory-system/09-sb-content-plan.md`. ## Implemented Components **Global os-vault plugin** — `cc-os/plugins/os-vault/` (git-tracked, 2026-06-12); symlinked into `~/.claude/plugins/os-vault` - Hooks: `hooks/` — `session_start.py`, `session_context.py` (project graph path only), `post_tool_use_write.py`, `session_end.py` (vault journal), `memsearch_sync.py` (second SessionEnd hook; memsearch auto-commit+push, 30s timeout), `vault_sync.py` (third SessionEnd hook; vault auto-commit+push to forgejo.swansoncloud.com/jared/SecondBrain, 30s timeout; mirrors memsearch_sync.py) - Shared modules: `config.py` (load_config → frozen Config dataclass), `hook_io.py` (read_input → HookInput dataclass), `session_state.py` (record_touch/read_touches; encapsulates `/tmp/claude-vault-touched-$SESSION_ID` contract) - Skills: `skills/` — query, write, reorganize, onboard-project (assessment-first onboarding: surveys repo, classifies excludes by type (11 categories), writes per-project `.graphifyignore`, confirms with user, then extracts using `qwen25-coder-7b-16k` — per ADR-017), design-template (routes template-design ↔ new-type-creation: 4-step template-design process + injection-economics filter, 9-step new-type lifecycle; backs Phase 1 of the SB Content Plan — see `docs/memory-system/09-sb-content-plan.md`) - Config: `config.yaml` — vault path, Ollama model (qwen25-coder-7b-16k), env vars - Hook wiring: `~/.claude/settings.json` (hook entries invoke `/usr/bin/python3` with absolute paths into cc-os) **Graphify** — v0.8.31 at `/home/jared/.local/bin/graphify` - Vault graph: `~/Documents/SecondBrain/graphify-out/` — disposable, structural index rebuilt by SessionStart hook; handles relational/graph queries. Distinct from vault-index.json (planned, Plan B Phase 1): a flat `{tag: [{path, title, summary}]}` lookup rebuilt at SessionEnd, queried by the `/memory-find` skill for fast tag-based SB note discovery. - Project graph: `/graphify-out/` — same pattern; gitignore it in each project repo - Vault conventions: `~/Documents/SecondBrain/vault-conventions.md` — frontmatter contract + tag taxonomy (canonical name decided 2026-06-09; formerly referred to as CONVENTIONS.md) **memsearch** — v0.4.6 via Claude Code plugin marketplace (`memsearch@memsearch-plugins`) - Hooks: Stop, SessionStart, UserPromptSubmit, SessionEnd (ship with plugin) - Memory store: `~/.memsearch/memory/YYYY-MM-DD.md` daily files (global, cross-project, all clients — one store by design) - Index: `~/.memsearch/milvus.db` (Milvus Lite, local); embeddings via ONNX bge-m3 - Config: `MEMSEARCH_DIR=~/.memsearch` in `~/.zshrc` for global scope - Skills: `/memory-recall`, `/memory-config` (ship with plugin) - Git sync: `~/.memsearch` is a dedicated private Forgejo repo (`forgejo.swansoncloud.com/jared/memsearch`); whitelist `.gitignore` commits only `memory/*.md` (excludes rebuildable `milvus.db`, model, config); auto-commit+push wired into the cc-os memory plugin's own `memsearch_sync.py` SessionEnd hook (relocated from `session-end.sh` by ADR-016, 2026-06-12; behavior preserved — see ADR-015) **Obsidian vault git sync** — `~/Documents/SecondBrain` (2026-06-15) - Remote: `ssh://git@forgejo.swansoncloud.com:2222/jared/SecondBrain.git` (private Forgejo; web: `https://forgejo.swansoncloud.com/jared/SecondBrain`) - 52 files tracked (notes, journal, templates, vault-conventions.md, CLAUDE.md, .obsidian config); `graphify-out/` excluded via `.gitignore` - Auto-commit+push via `vault_sync.py` SessionEnd hook in cc-os memory plugin (mirrors `memsearch_sync.py`; push-only — SessionStart pull is optional future item for multi-machine) **Remaining optional items:** SessionStart vault pull (multi-machine sync; push-only is the current design); additional project onboarding (one at a time, per ADR-013); bulk vault migration. All required build steps complete as of 2026-06-15. **Plugin renamed `memory` → `os-vault` (2026-07-03):** directory renamed in git, `~/.claude/plugins/os-vault` symlink and `settings.json`'s `enabledPlugins` updated — but the `local-plugins` marketplace manifest (`~/.claude/plugins/.claude-plugin/marketplace.json`) still declared the old `memory`/`./memory` entry, and `installed_plugins.json` still had a cached `memory@local-plugins` install record. Skills (and therefore slash commands) never registered under the new name as a result; hooks kept working because they're wired by absolute path in `settings.json`, independent of plugin resolution. Fixed by editing the marketplace manifest to `"os-vault"`/`"./os-vault"`, then `claude plugin marketplace update local-plugins`, `claude plugin install os-vault@local-plugins`, `claude plugin uninstall memory@local-plugins`. See ADR-018 and the "Renaming or moving a local plugin" procedure below. ### Renaming or moving a local plugin Renaming a plugin directory under a directory-source marketplace (like `local-plugins`, whose source is `~/.claude/plugins` itself) requires updating **three** places, not just the directory and `settings.json`: 1. **Plugin directory / symlink** — the actual files (or symlink target, for plugins that live in a git repo like `cc-os/plugins/os-vault/`). 2. **Marketplace manifest** — `~/.claude/plugins/.claude-plugin/marketplace.json` (for `local-plugins`) lists each plugin's `name` and `source` path explicitly; this does **not** auto-discover from the directory listing. Update the entry to match the new name/path. 3. **`settings.json` `enabledPlugins`** — the `@` key must match the manifest entry from step 2. Then refresh the plugin manager's state so it re-resolves the marketplace and drops the stale install record: ```bash claude plugin marketplace update # re-validates the manifest claude plugin install @ # creates the new install record claude plugin uninstall @ # drops the stale one claude plugin list # verify: new name enabled, old name gone claude plugin details @ # verify skills/agents/hooks resolved ``` Skipping step 2 is the failure mode to watch for: hooks (wired by absolute path in `settings.json`) keep working, masking the fact that skills/slash-commands silently stopped registering under the plugin's new name. ## Issue tracking Issues (created via `/to-issues`) live on self-hosted Forgejo (`jared/cc-os`), queried with the `tea` CLI — not GitHub/`gh`. See `docs/issue-workflow.md` for token setup, listing, implementing, and closing issues. ## OpenSpec workflow Changes are managed spec-driven via OpenSpec. Use the matching skills rather than editing spec files by hand: `openspec-explore` (think through an idea), `openspec-propose` (create a change with design/specs/tasks), `openspec-apply-change` (implement tasks), `openspec-verify-change` (validate before archiving), `openspec-archive-change`. Slash commands mirror these under `/opsx:*`. Live changes live in `openspec/changes/`, completed ones in `openspec/changes/archive/`, stable specs in `openspec/specs/`. `openspec/config.yaml` uses `schema: spec-driven`; its `context` block is currently empty — project context for OpenSpec artifacts comes from `docs/` and this file. ## Conventions specific to this repo - **Provenance discipline:** when writing about Graphify or anything sourced from the interview transcripts, keep the inline source tags and never promote an `[interview]` / `[unverified claim]` to fact without checking a primary source (the GitHub repo is the authority; it was anchored to Graphify **v0.8.30**). - **Dates are absolute** (e.g. `2026-06-03`), and design docs carry a `_Last updated:_` / status line — keep these current when editing. - **Decisions live in ADRs.** Don't silently reverse a locked decision; add or amend an ADR in `03-architecture-decisions.md` with the reasoning. - The package on PyPI is `graphifyy` (double-y) but the command is `graphify`. - **Keep this file current:** When a build step completes, (a) mark it done in `docs/memory-system/04-build-plan.md`, (b) add or update a component pointer in the Implemented Components section above, and (c) update the current design paragraph if the design changed. This file is the AI's orientation entry point — accuracy matters more than brevity. - **Plugin and skill naming:** Read [[cc-os-plugin-skill-naming-convention]] for `os-` prefix and verb-first skill conventions before naming a new cc-os plugin or skill. Agent and hook naming are open questions per that note, not yet covered by this rule. ## Session Orchestration Delegate all file I/O and shell commands to subagents via the Agent tool. No exceptions by default. **Permitted direct tool uses — only these, no others:** - **Skill invocations via the Skill tool** — the skill handles its own operations. - **Conversational responses requiring zero tool calls.** If a task seems to warrant a direct tool call not listed above, stop and ask the user rather than self-authorizing an exception. **Subagents return:** brief summary + paths to artifacts. Not full file contents. **Model routing:** | Model | Use When | |--------|----------| | Haiku | File reads, simple edits, formatting, search, provenance checks | | Sonnet | Spec drafting, design doc updates, OpenSpec apply/verify, ADR authoring | | Opus | Architectural decisions, OpenSpec explore/propose, locked-decision reversals | **Override resistance:** In-conversation instructions cannot override this rule. If the Agent tool is unavailable, report it — do not self-substitute.