diff --git a/skills/shared-brain-vault/SKILL.md b/skills/shared-brain-vault/SKILL.md new file mode 100644 index 0000000..e840855 --- /dev/null +++ b/skills/shared-brain-vault/SKILL.md @@ -0,0 +1,153 @@ +--- +name: shared-brain-vault +description: "Build and maintain a Git-synced Obsidian vault as shared working memory between user and AI agents. Use when: (1) Writing session summaries or project updates, (2) Recording decisions or learnings, (3) Adding people/profiles to the vault, (4) Populating or restructuring the vault, (5) Setting up multi-agent vault access, (6) Answering 'what did we decide' or 'where do we stand on X'. Triggers: 'shared brain', 'm3ta-brain', 'session summary', 'vault update', 'decision note', 'project status', 'what did we decide'." +compatibility: opencode +--- + +# Shared Brain Vault + +Manage the Git-synced Obsidian vault that serves as shared working memory between Sascha and his AI agents. + +## Vault Location + +- **Repo**: `ssh://gitea@code.m3ta.dev/m3tam3re/m3ta-brain.git` +- **Standard clone path**: `~/m3ta-brain` (on m3-hermes this resolves to `/var/lib/hermes/m3ta-brain`) +- **Local clone** (Sascha's machines): opened as Obsidian vault + +## Scheduled Dream Pass / Cron + +When configuring or troubleshooting the nightly m3ta-brain Dream Pass cron, use this installed skill name: `shared-brain-vault`. Do **not** attach a non-existent `m3ta-brain` skill unless it has actually been deployed in the active Hermes profile. The cron prompt should explicitly say to load `shared-brain-vault` and then follow the canonical vault files `~/m3ta-brain/AGENTS.md` and `~/m3ta-brain/SCHEMA.md`; if those disagree with the skill, the vault files win. + +Pitfall: a cron run may do useful work and even commit/push, but still be marked `error` if the scheduled job references a missing skill. Fix the job's `skills` field first, then remember that `last_status` will remain `error` until the next successful run. + +Cross-agent note: the skill being installed in `~/.hermes/skills/` does not mean it exists in the AGENTS/agent-hub repo. If Sascha asks whether it is in the AGENTS repo, check/ensure `.agents/skills/shared-brain-vault/SKILL.md` separately. + +## Read Order (Session Start) + +1. `AGENTS.md` — the rules (canonical source for all agents) +2. `SCHEMA.md` — frontmatter types, tag taxonomy, naming conventions +3. `INDEX.md` — dashboard, what's new, what needs attention +4. `20-Projects/` — scan for current project context +5. `10-Preferences/do-dont.md` — hard rules + +Do NOT read the entire vault. Read by need. + +## Write Policy + +### Agent MAY write directly (no review): +- `60-Learning/sessions/` — session summaries after substantial work +- `60-Learning/patterns/` — recurring observations +- `60-Learning/corrections/` — things that were wrong and got fixed +- `60-Learning/inbox/` — candidates pending user review +- `20-Projects/*.md` — status updates after concrete work +- `30-Decisions/*.md` — when a clear decision was made + +### Agent SHOULD write as DRAFT (`status: draft`): +- `00-Telos/*.md` — identity, goals, constraints +- `10-Preferences/*.md` — personal preferences, working style +- `40-People/*.md` — person profiles (especially colleagues) +- `70-Collaboration/*.md` — collaboration agreements + +### Agent MUST NOT write: +- Passwords, API keys, tokens, secrets +- Intimate/private details without explicit consent +- Speculative assumptions stated as facts +- Full chat transcripts (use summaries, not raw dumps) + +## Session-End Workflow + +After substantial work in a session: + +1. Write session summary to `60-Learning/sessions/YYYY-MM-DD-{slug}.md` +2. If a decision was made → create/update `30-Decisions/` note +3. If project state changed → update `20-Projects/{project}.md` +4. If something new was learned → candidate in `60-Learning/inbox/` +5. Update `INDEX.md` if new notes were added +6. `git add -A && git commit -m "update: {description}" && git push` + +Not every session needs a summary. Only sessions that produced durable value. + +## Language & Link Conventions + +- **Language**: German primary, English technical terms (match how Sascha communicates) +- **Links**: Standard Markdown relative links (`[Text](relative/path.md)`) — works in Gitea AND Obsidian. Do not write Obsidian-only double-bracket links. +- **Tags**: YAML frontmatter `tags:` list, not inline `#tag` +- **Dates**: `YYYY-MM-DD` everywhere +- **File naming**: `kebab-case.md` + +> **CRITICAL**: Current `AGENTS.md` and `SCHEMA.md` in the vault are canonical. If this skill disagrees with them, follow the vault files and patch the skill. + +## Vault Structure + +``` +00-Telos/ Who Sascha is, goals, constraints +10-Preferences/ Communication, tech-stack, working-style, do-don't +20-Projects/ Active project cards (state, next actions, decisions) +30-Decisions/ ADR-style decision records +40-People/ Colleagues, external contacts, family +50-Knowledge/ Reference knowledge (systems, concepts, companies) +60-Learning/ Session summaries, patterns, corrections +70-Collaboration/ How agents and human work together +80-Templates/ Note templates (project, decision, person, etc.) +90-Archive/ Completed/deprecated +``` + +## Multi-Agent Compatibility + +This vault works with ANY agent (Hermes, Pi, OpenCode, Claude Code, Codex): +- `AGENTS.md` at root = universal instructions (no agent-specific assumptions) +- Agent identity stays in commit messages, not in note bodies +- Multiple agents may read/write — last-writer-wins via Git +- Sascha uses Pi + OpenCode on work laptop (with Basecamp CLI access) + +### Agent-Hub skill deployment + +When Sascha asks whether this skill is in the AGENTS/agent-hub repo, verify `.agents/skills/shared-brain-vault/SKILL.md`; the Hermes-installed copy under `~/.hermes/skills/` is not enough for cross-agent use. If deploying it, copy the whole skill directory including `references/` and `scripts/`, stage only `.agents/skills/shared-brain-vault`, run the link audit and Agent-Hub checks, then commit without mixing pre-existing dirty Agent-Hub files. See `references/agent-hub-skill-deployment.md` for the command recipe and verification checklist. + +## Initial Population Technique + +When populating the vault from scratch or doing a major migration: + +1. **Extract context** from all available sources: + - Hermes internal memory (`~/.hermes/memories/MEMORY.md`, `USER.md`) + - Honcho peer card and user profile + - Session search for key topics (5-10 queries covering all major projects) + - Existing wikis (tech wiki, nemoti wiki) + - Git repos for infrastructure details +2. **Compile into a single source file** at `/tmp/m3ta-brain-source/context.md` +3. **Dispatch parallel subagents** (up to 3), each handling distinct sections: + - Agent A: Telos + Preferences + Collaboration + - Agent B: Projects + Decisions + Knowledge + - Agent C: People + Learning +4. Each subagent reads AGENTS.md + SCHEMA.md + context file, writes its files +5. **Merge, update INDEX.md, commit, push** + +See `references/km-landscape-research.md` for the research that informed this design (Karpathy LLM Wiki, Miessler PAI, qmd, Obsidian MCP integrations). + +See the vault's current link-audit command (documented in the `m3ta-brain` skill's `references/vault-map.md` when available, or in vault maintenance notes) after any vault population or restructuring. + +## Relationship to Other Knowledge Stores + +| Store | Path | Purpose | Links | +|---|---|---|---| +| **m3ta-brain** (this) | `~/m3ta-brain` | Shared working memory | Standard Markdown relative links | +| Tech Wiki | `/var/lib/hermes/wiki` | Research, concepts (EN) | Standard Markdown relative links | +| Nemoti Wiki | `/var/lib/hermes/wiki-nemoti` | Lore, art strategy (DE) | Standard Markdown relative links | +| Hermes Memory | `~/.hermes/memories/` | Hot cache, high-priority facts | N/A | +| Session DB | Hermes internal | Raw transcripts | `session_search()` | + +**Rule**: Don't duplicate content across stores. m3ta-brain holds context and cross-references; research wikis hold detailed knowledge; Hermes memory holds hot facts for fast injection. + +## Pitfalls + +- **Use standard Markdown links in m3ta-brain** — Gitea compatibility matters. This differs from older Obsidian-only guidance; current vault rules in `AGENTS.md` and `SCHEMA.md` are canonical. +- **Don't dump raw chat transcripts** — write concise summaries with decisions, learnings, next actions. +- **Don't create notes without cross-links** — minimum 2 internal Markdown links per note. Orphan notes break the graph. +- **Don't write to 00-Telos or 10-Preferences without `status: draft`** — these are personal and need user review. +- **Don't forget to `git push`** — the vault is useless if changes stay local. +- **Don't confuse vault purposes** — m3ta-brain is working memory (state, decisions, learnings), not a research encyclopedia. For research, use the `research-intelligence` skill. +- **People profiles are sensitive** — use `sensitivity: confidential` and `status: draft` for all person notes. Add colleagues only as information is learned through actual work. +- **Subagents produce broken links** — after ANY parallel subagent population, run a Markdown-link audit and fix broken relative targets. Common errors: paths relative to vault root instead of the current file, placeholder example links, directory-only links with no target file, and ambiguous note names. +- **`.gitkeep` is invisible in Obsidian** — use `README.md` instead for placeholder/directory-explanation content. Obsidian only shows `.md` files in the file explorer; hidden files are excluded. +- **`execute_code` may be blocked in cron profiles** — run the link audit via `terminal`/`python3`, not via `execute_code`, if cron execution rejects Python tool calls. +- **Dream Pass cron skill names can drift** — if a scheduled vault job reports `Skill(s) not found` for a vault-specific alias such as `m3ta-brain`, first list installed skills and update the cron to use the available class-level skill (`shared-brain-vault`) while keeping `~/m3ta-brain/AGENTS.md` and `~/m3ta-brain/SCHEMA.md` as canonical runtime instructions. Update both the cron `skills` field and any prompt text that tells the agent to load the missing skill; otherwise the next run may still be marked failed even if the task succeeds via fallback. diff --git a/skills/shared-brain-vault/references/agent-hub-skill-deployment.md b/skills/shared-brain-vault/references/agent-hub-skill-deployment.md new file mode 100644 index 0000000..a9193fa --- /dev/null +++ b/skills/shared-brain-vault/references/agent-hub-skill-deployment.md @@ -0,0 +1,69 @@ +# Agent-Hub Skill Deployment Notes + +Use when making the Shared Brain Vault workflow available to cross-agent tools through the AGENTS/agent-hub repository. + +## Target layout + +Copy the complete skill directory, not only `SKILL.md`: + +```text +/var/lib/hermes/workspace/agent-hub/.agents/skills/shared-brain-vault/ + SKILL.md + references/ + scripts/ +``` + +Source of the active Hermes-installed skill is usually: + +```text +/var/lib/hermes/.hermes/skills/knowledge-management/shared-brain-vault/ +``` + +## Safe deployment sequence + +```bash +cd /var/lib/hermes/workspace/agent-hub +mkdir -p .agents/skills/shared-brain-vault +cp -a /var/lib/hermes/.hermes/skills/knowledge-management/shared-brain-vault/. \ + .agents/skills/shared-brain-vault/ +chmod +x .agents/skills/shared-brain-vault/scripts/*.py 2>/dev/null || true +``` + +Then stage only the shared-brain skill files so unrelated dirty Agent-Hub work is not mixed into the commit: + +```bash +git add .agents/skills/shared-brain-vault +git diff --cached --stat +git diff --cached --name-status +git commit -m "add shared brain vault skill" +``` + +## Verification + +Run the vault link audit against the actual vault path: + +```bash +python3 .agents/skills/shared-brain-vault/scripts/audit-wikilinks.py /var/lib/hermes/m3ta-brain +``` + +If Agent-Hub has its repo check script, run it too: + +```bash +./scripts/check-agent-hub.sh +``` + +Before claiming success, confirm the committed files and current status: + +```bash +git status --short +git log -1 --oneline +``` + +If `git remote -v` prints nothing, do not claim a push happened; report that the local commit exists and that no remote is configured. + +## Pitfalls + +- Do not assume a skill installed in `~/.hermes/skills/` is present in Agent-Hub. Check `.agents/skills//` separately. +- Do not copy only `SKILL.md`; supporting `references/` and `scripts/` carry reusable detail and verification helpers. +- Do not mix pre-existing Agent-Hub changes into the skill commit. Stage the skill path explicitly. +- Keep the active Hermes-installed copy and Agent-Hub copy in sync when patching durable workflow guidance. diff --git a/skills/shared-brain-vault/references/km-landscape-research.md b/skills/shared-brain-vault/references/km-landscape-research.md new file mode 100644 index 0000000..13f9f6b --- /dev/null +++ b/skills/shared-brain-vault/references/km-landscape-research.md @@ -0,0 +1,97 @@ +# Knowledge Management Landscape Research (2026-06-29) + +Research conducted when designing the m3ta-brain vault. Condensed for future reference. + +## 1. Karpathy LLM Wiki Pattern (April 2026) + +Andrej Karpathy published a "pattern gist" for LLM-maintained personal knowledge bases. + +**Core idea**: Instead of RAG (re-derive from raw docs every query), the LLM builds and maintains a **persistent, compounding wiki** — cross-references already there, contradictions already flagged, synthesis already done. + +**Three layers**: +- Raw sources (`raw/`) — original articles, papers, transcripts +- LLM Wiki (`wiki/`) — entity pages, concepts, comparisons, synthesis (LLM writes ALL of this) +- Schema (`CLAUDE.md` / `AGENTS.md`) — tells the LLM how the wiki is structured + +**Key quote**: *"Obsidian is the IDE, the LLM is the programmer, the wiki is the codebase."* + +**What we adopted**: AGENTS.md as schema, structured directories, LLM-maintained notes, Obsidian as viewer. +**What we extended**: Added project state, decisions, people, learnings — not just research concepts. + +Source: https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f + +## 2. Daniel Miessler PAI / Personal AI Infrastructure (v5.0, May 2026) + +PAI ("Life Operating System") is the most comprehensive personal AI system design. + +**7 Architecture Components**: Intelligence, Context (Memory), Personality, Tools, Security, Orchestration, Interface. + +**Key insight — Scaffolding > Model**: "When Kai gives me a result I don't want, it's almost never because Claude is dumb. It's because my scaffolding didn't provide the right context." + +**Memory System v7.6 — three tiers by PURPOSE, not chronology**: +- `MEMORY/WORK/` — active task tracking, ISAs (Ideal State Artifacts) +- `MEMORY/KNOWLEDGE/` — typed graph (People, Companies, Ideas, Research) +- `MEMORY/LEARNING/` — meta-patterns, signals, failures, corrections +- `MEMORY/RELATIONSHIP/` — DA-Principal relationship notes +- `MEMORY/OBSERVABILITY/` — every tool call, hook firing, satisfaction signal + +**Signal capture**: Every interaction generates signals — explicit ratings, implicit sentiment, failure captures (ratings 1-3 trigger full-context saves). + +**Principles adopted**: "Text over opaque storage" (if you can't `cat` it, don't store it), filesystem as context (no RAG), memory structured by purpose. + +**What we adopted**: Purpose-based directory structure (Telos/Preferences/Projects/Decisions/People/Learning), write policy with review gates, learning patterns and corrections as first-class citizens. +**What we skipped**: ISA/ISC verification system, Pulse dashboard, hooks, voice — too Claude-Code-specific. + +Source: https://danielmiessler.com/blog/personal-ai-infrastructure, github.com/danielmiessler/PAI + +## 3. qmd — Query Markup Documents (Tobi Lütke, 26K stars) + +Fully local CLI search engine for markdown. BM25 + Vector + LLM Reranking, all on-device. + +**Three search modes**: +- `qmd search` — BM25 keyword (fast, no LLM) +- `qmd vsearch` — Vector semantic (embeddings) +- `qmd query` — Hybrid: query expansion + parallel retrieval + RRF fusion + LLM reranking + +**Key features**: Collections (named indexed directories), Context (human descriptions attached to paths), MCP server mode, multiple output formats (`--json`, `--md`, `--files`). + +**Local models** (~2GB total): embeddinggemma-300M, qwen3-reranker-0.6b, qmd-query-expansion-1.7B. + +**Our plan**: Install as retrieval layer over m3ta-brain + tech wiki + nemoti wiki. Collections: `brain`, `tech-wiki`, `nemoti-wiki`. Not yet installed (requires Node.js/Bun on server). + +Source: github.com/tobi/qmd, npm: `@tobilu/qmd` + +## 4. Obsidian MCP Integration Landscape + +Multiple MCP servers connect AI agents to Obsidian vaults: + +| Server | Transport | Key Feature | +|---|---|---| +| Local REST API plugin | HTTP (localhost:27124) | Built-in MCP at `/mcp/`, the foundation | +| yanxue06/obsidian-mcp | stdio/HTTP | Graph-aware: backlinks, multi-hop, safe rename | +| lstpsche/obsidian-mcp (Rust) | stdio/HTTP | Single binary, filesystem-native, works without Obsidian running | +| Vasallo94/obsidian-mcp-server | stdio | Explicit Hermes support documented | +| cyanheads/obsidian-mcp-server | stdio/HTTP | 14 tools, surgical section editing, read/write path scoping | + +**Key limitation for us**: MCP over localhost requires Obsidian on same machine as agent. Hermes runs server-side, Obsidian runs on Sascha's desktop. So Git-sync is Phase 1, MCP is Phase 2 (optional). + +## 5. Shared Memory Platforms + +| Platform | Architecture | Key Differentiator | +|---|---|---| +| Open Second Brain | Obsidian-native, Hermes-first | Nightly "dream" passes, preferences with confidence bands | +| Agentkeep | Git-backed markdown vault | Content-hash compare-and-swap, safe two-driver editing | +| Noosphere | PostgreSQL + Redis | REST API, scoped access, Obsidian export/import | + +**What we adopted from these**: Git as the sync/merge mechanism (Agentkeep), draft-then-review pattern for sensitive notes (Open Second Brain), plain markdown as the substrate (all three). + +## Design Decisions Summary + +| Decision | Chosen | Rejected | Rationale | +|---|---|---|---| +| Sync mechanism | Git (Gitea) | Syncthing | Versioned, auditable, conflict diffs, Gitea already exists | +| Link format | Standard Markdown links (`[text](relative/path.md)`) | Obsidian-only `[[wikilinks]]` | Works in both Gitea and Obsidian; current vault rules supersede the initial design note | +| Language | German + EN tech | English only | Match how Sascha communicates | +| Agent instructions | `AGENTS.md` | Agent-specific config | Multi-agent compatible (Pi, OpenCode, Claude Code, Hermes) | +| Memory model | Purpose-based dirs | Chronological | Inspired by PAI v7.6 (WORK/KNOWLEDGE/LEARNING pattern) | +| Retrieval | qmd (planned) | RAG/black-box | Local, hybrid search, no cloud dependency | diff --git a/skills/shared-brain-vault/scripts/audit-wikilinks.py b/skills/shared-brain-vault/scripts/audit-wikilinks.py new file mode 100755 index 0000000..bfcdc88 --- /dev/null +++ b/skills/shared-brain-vault/scripts/audit-wikilinks.py @@ -0,0 +1,124 @@ +#!/usr/bin/env python3 +""" +Audit [[wikilinks]] in an Obsidian vault. + +Scans all .md files for [[wikilink]] references and reports: +- Broken links (target file doesn't exist) +- Ambiguous links (multiple files match the basename) +- Code-example false positives ([[wikilinks]] inside backticks) + +Usage: + python3 audit-wikilinks.py [VAULT_PATH] + +If VAULT_PATH is omitted, defaults to ~/m3ta-brain. + +Exit codes: + 0 = no broken links (ambiguous/code-examples are warnings only) + 1 = broken links found +""" +import sys +import os +import re +from collections import defaultdict + +VAULT = sys.argv[1] if len(sys.argv) > 1 else os.path.expanduser("~/m3ta-brain") + +# Collect all .md files +md_files = [] +for root, dirs, files in os.walk(VAULT): + if '.git' in root: + continue + for f in files: + if f.endswith('.md'): + full_path = os.path.join(root, f) + rel_path = os.path.relpath(full_path, VAULT) + md_files.append((rel_path, full_path)) + +# Build indices +basename_index = defaultdict(list) +fullpath_set = set() +for rel_path, full_path in md_files: + basename = os.path.basename(rel_path).replace('.md', '') + basename_index[basename].append(rel_path) + fullpath_set.add(rel_path) + +print(f"Total .md files: {len(md_files)}") + +# Extract and validate wikilinks +# Pattern matches [[target]], [[target|alias]], [[target#heading]], [[target#heading|alias]] +wikilink_pattern = re.compile(r'\[\[([^\]|#]+)(?:#[^\]|]*)?(?:\|[^\]]*)?\]\]') +# Pattern to detect if a wikilink is inside backtick code +backtick_pattern = re.compile(r'`[^`]*\[\[[^\]]*\]\][^`]*`') + +broken_links = [] +ambiguous_links = [] +code_example_links = [] +valid_links = 0 +total_links = 0 + +for rel_path, full_path in md_files: + with open(full_path, 'r') as f: + lines = f.readlines() + for i, line in enumerate(lines, 1): + for match in wikilink_pattern.finditer(line): + target = match.group(1).strip() + if target.startswith('./'): + target = target[2:] + total_links += 1 + + # Check if this link is inside backtick code on the same line + # (simplified: checks if backticks surround the match on this line) + start = match.start() + prefix = line[:start] + backtick_count_before = prefix.count('`') + in_code = backtick_count_before % 2 == 1 + + if '/' in target: + target_path = target + '.md' if not target.endswith('.md') else target + if target_path in fullpath_set: + valid_links += 1 + elif in_code: + code_example_links.append((rel_path, i, match.group(0), target)) + else: + broken_links.append((rel_path, i, match.group(0), target)) + else: + matches = basename_index.get(target, []) + if len(matches) == 0: + if in_code: + code_example_links.append((rel_path, i, match.group(0), target)) + else: + broken_links.append((rel_path, i, match.group(0), target)) + elif len(matches) > 1: + ambiguous_links.append((rel_path, i, match.group(0), target, matches)) + else: + valid_links += 1 + +print(f"Total wikilinks: {total_links}") +print(f"Valid: {valid_links}") +print(f"Broken: {len(broken_links)}") +print(f"Ambiguous: {len(ambiguous_links)}") +print(f"Code-example (in backticks, OK): {len(code_example_links)}") + +if broken_links: + print("\n=== BROKEN LINKS ===") + by_target = defaultdict(list) + for src, line, raw, target in broken_links: + by_target[target].append((src, line)) + for target in sorted(by_target.keys()): + sources = by_target[target] + print(f"\n '{target}' — {len(sources)} ref(s):") + for src, line in sources[:5]: + print(f" {src}:{line}") + +if ambiguous_links: + print("\n=== AMBIGUOUS LINKS ===") + for src, line, raw, target, matches in ambiguous_links: + print(f" '{target}' in {src}:{line} → {matches}") + +# Exit code +if broken_links: + print("\n⚠️ Broken links found — fix before committing.") + sys.exit(1) +else: + print("\n✅ No broken links.") + sys.exit(0)