21 KiB
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.mdis the architecture,03-architecture- decisions.mdis the ADR log (each decision + what was rejected/deferred and why),04-build-plan.mdis the build outline,06-graphify-evaluation.mdjustifies 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. Skim00-README.mdfor the model, keep09-best-practices-checklist.mdopen 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 indocs/.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_IDcontract) - 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 usingqwen25-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 — seedocs/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/python3with absolute paths into cc-os)
Global os-orchestration plugin — cc-os/plugins/os-orchestration/ (git-tracked, 2026-07-03); symlinked into ~/.claude/plugins/os-orchestration
- Hooks:
hooks/—inject.py(injectsORCHESTRATION.mdas additionalContext to all sessions) - Behavior: SessionStart hook injects an
ORCHESTRATION.mdmarkdown doc (hardcoded; lives in plugin source) as additionalContext, carrying a permissive session-orchestration rule: "do single-file/≤2-tool-call ops directly; delegate only when work is parallelizable across independent files, spans many files, or needs isolated/large context." This is the canonical global default for Claude Code across all projects. - Migration: migrated from a standalone repo (
~/dev/cc-plugins/orchestration/, 2026-07-03) and integrated into cc-os. Supersedes the per-project copy-pasted orchestration text blocks that previously existed in individual project CLAUDE.md files (including a stricter local override that cc-os had carried — now removed; see ADR-019).
Global os-doc-hygiene plugin — cc-os/plugins/os-doc-hygiene/ (git-tracked, 2026-07-03); symlinked into ~/.claude/plugins/os-doc-hygiene
- Hooks:
hooks/hooks.json→ SessionStart hook (matcher: startup|resume) runsscripts/reminder.pyvia${CLAUDE_PLUGIN_ROOT}(5s timeout), emitting a deterministic zero-token reminder banner - Behavior: Monitors stale and bloated project documentation per-project under
.dochygiene/state dir (gitignored). SessionStart reminder is deterministic (no AI tokens, once/day snooze). Skills (verb-first, nocommands/dispatcher — invoked directly as/os-doc-hygiene:<skill>, per cc-os-plugin-skill-naming-convention):check(AI-assisted classification of staleness signals, emits machine+human reports),clean(AI-assisted or deterministic patch application with git-safe scoped cleanup),status(read-only lifecycle-timestamp read),sweep(check then clean in sequence). Reversion-protected via invariants.md + golden-example test fixtures. - Migration: migrated from standalone repo (
~/dev/cc-plugins/doc-hygiene/, 2026-07-03) and integrated into cc-os. No content conflicts detected (doc-hygiene scope does not overlap cc-os memory system). Renamed fromdoc-hygienetoos-doc-hygieneper cc-os plugin naming convention. Skills renamedhygiene-check/hygiene-clean→check/clean, and thecommands/hygiene.mddispatcher removed in favor of two new skills (status,sweep), aligning with theos-vault/os-orchestrationpattern of nocommands/directory (2026-07-03).
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-findskill for fast tag-based SB note discovery. - Project graph:
<project-root>/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.mddaily 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=~/.memsearchin~/.zshrcfor global scope - Skills:
/memory-recall,/memory-config(ship with plugin) - Git sync:
~/.memsearchis a dedicated private Forgejo repo (forgejo.swansoncloud.com/jared/memsearch); whitelist.gitignorecommits onlymemory/*.md(excludes rebuildablemilvus.db, model, config); auto-commit+push wired into the cc-os memory plugin's ownmemsearch_sync.pySessionEnd hook (relocated fromsession-end.shby 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.pySessionEnd hook in cc-os memory plugin (mirrorsmemsearch_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:
- Plugin directory / symlink — the actual files (or symlink target, for plugins that live in
a git repo like
cc-os/plugins/os-vault/). - Marketplace manifest —
~/.claude/plugins/.claude-plugin/marketplace.json(forlocal-plugins) lists each plugin'snameandsourcepath explicitly; this does not auto-discover from the directory listing. Update the entry to match the new name/path. settings.jsonenabledPlugins— the<name>@<marketplace>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:
claude plugin marketplace update <marketplace-name> # re-validates the manifest
claude plugin install <new-name>@<marketplace-name> # creates the new install record
claude plugin uninstall <old-name>@<marketplace-name> # drops the stale one
claude plugin list # verify: new name enabled, old name gone
claude plugin details <new-name>@<marketplace-name> # 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.mdwith the reasoning. - The package on PyPI is
graphifyy(double-y) but the command isgraphify. - 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 behavior — Provided by the global os-orchestration plugin (see Implemented Components below). This repo no longer carries a local orchestration override; it follows the plugin's default behavior like every other project.