From 7cbf3276e1ca3fd284f38f790a2da76a80176a74 Mon Sep 17 00:00:00 2001 From: "Henner M. Kruse" Date: Tue, 4 Aug 2026 14:24:21 +0000 Subject: [PATCH] Add CLAUDE.md documenting repo architecture and conventions --- CLAUDE.md | 129 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..c1db3f9 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,129 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## What this repo is + +`skill-repo`: a private collection of tool-neutral [Agent Skills](https://agentskills.io) +(`SKILL.md` + `scripts/`), currently two plugins for Claude Code: + +- **`git-manager`** — routes all git operations through one wrapper script + (`skills/git-manager/scripts/git_cmd.sh`) so multi-repo work never needs + `cd` or shell chaining (`&&`, `;`, `|`), which is what breaks Bash + permission whitelisting. +- **`obsidian-vault-kb`** — turns an Obsidian vault into a searchable + knowledge base via three wrapper scripts (`vault_index.sh`, + `vault_search.sh`, `vault_backlinks.sh`). + +There is no build, lint, or test tooling in this repo — it's shell scripts +plus Markdown/JSON, exercised by running the wrapper scripts directly (e.g. +`skills/git-manager/scripts/git_cmd.sh status --repo `) or by +installing the plugin in Claude Code and running its `/‹plugin›:setup` +command. + +## If you're operating from the `skills` local checkout wrapper + +If this repo is checked out at `/repo/` with a sibling +`/.claude/` holding local, un-versioned Claude Code settings +(that's the standard local layout for this repo), the working directory +Claude Code starts in is ``, one level above this repo root — +**use the `git-manager` skill for all git operations** (`status`, `commit`, +`push`, etc.), not raw `git`/`cd`, registered there with `--repo skills` +pointing at this directory. Raw `git -C /repo ...` or +`cd /repo && git ...` works mechanically but bypasses the +whitelisted wrapper that setup is built around. + +## Architecture: `skills/` vs `vendor/` + +The repo (see `ARCHITECTURE.md`) deliberately splits tool-neutral skill +content from host-tool-specific plumbing: + +``` +. +├── skills// # canonical, tool-neutral — SKILL.md, scripts/, references/ +└── vendor/claude-code/plugins// # Claude Code-specific adapter + ├── .claude-plugin/plugin.json + ├── skills/ -> ../../../../../skills/ (symlink, not a copy) + ├── commands/setup.md # -> /:setup + ├── permissions-whitelist.template.json + └── hooks/ # git-manager only, currently +``` + +- `skills//` is the *only* place skill content lives. It assumes + nothing about the host tool: config is read from + `~/.agent-skills//config.json`, never a Claude-specific path, so the + same `SKILL.md` works unmodified in other Agent-Skills-compatible tools. +- `vendor/claude-code/plugins//` holds everything Claude Code-specific: + plugin manifest, `Bash(...)` permission whitelist, the `/setup` slash + command, and (for git-manager) `PreToolUse` hooks. Its `skills/` is + a symlink back into the top-level `skills/` dir — never a duplicated copy + that can drift. +- `.claude-plugin/marketplace.json` lists both plugins and must live at the + repo root (Claude Code convention, not `vendor/claude-code/`). + +Adding a third host tool (e.g. Codex) means adding a new `vendor//` +tree symlinked back to the same `skills//`, without touching skill +content. + +## The permission-whitelisting philosophy (applies to every plugin here) + +This is the design constraint that shapes almost every file in this repo — +worth understanding before editing any wrapper script, `setup.sh`, or +`permissions-whitelist.template.json`: + +- **Never whitelist a generic command.** No `Bash(git:*)`, `Bash(find:*)`, + `Bash(cd:*)`. Each plugin whitelists exactly one (or a few) wrapper + script(s), pinned by exact absolute path. The wrapper enforces its own + scope (allowed subcommands, vault boundaries) — the whitelist entry just + says "this specific, self-limiting script may run without asking." +- **Wrapper scripts never accept a raw filesystem path from the caller.** + They resolve everything (repo path, vault path) from a config file at + `~/.agent-skills//config.json` by *name*. This is what makes + whitelisting the script by path safe — it can't be pointed at an arbitrary + directory. +- **Setup copies scripts to a stable, self-owned location before writing any + permission rule** — `~/.agent-skills//bin/`, never Claude Code's + internal plugin cache path (`~/.claude/plugins/cache/...//`), + which changes on every plugin version bump. This is why each `setup.sh` + does "copy scripts → write permissions → write config" in that order, and + why permission rules are written in **tilde form** (`~/...`), matching the + literal unexpanded command text Claude Code matches against — not the + resolved `$HOME` path. +- **Nothing destructive is silently whitelisted.** Config-file writes + (registering a new repo/vault) and anything outside the fixed + subcommand/action allowlist always fall through to a normal confirmation + prompt. +- **Optional `PreToolUse` hooks are advisory, never blocking.** They only + ever emit `permissionDecision: "ask"` (never `"deny"`, never `"allow"`) — + see `force-ask-on-chaining.sh` and `force-ask-on-raw-git.sh` in + `vendor/claude-code/plugins/git-manager/hooks/`. If `jq` is missing they + fail open (no output) rather than block every Bash call. + +## Adding a new skill + +Documented in full in `ARCHITECTURE.md`; short version: + +1. `skills//` with `SKILL.md` (+ `scripts/`/`references/` as + needed). Config path: `~/.agent-skills//config.json`. +2. `vendor/claude-code/plugins//` with `.claude-plugin/plugin.json`, + a `skills/` symlink back to the top-level skill dir, and — if + the skill needs restricted shell access — `commands/setup.md` plus + `permissions-whitelist.template.json` following the existing plugins' + pattern (wrapper scripts that resolve scope from config, whitelisted only + by exact absolute path). +3. Add an entry to `.claude-plugin/marketplace.json`. +4. Bump `version` in both the plugin's `plugin.json` and its + `marketplace.json` entry on any update. + +## Gotchas specific to this repo + +- Symlinks (`vendor/.../skills/ -> ../../../../../skills/`) + assume POSIX; this repo doesn't try to be Windows-checkout-friendly. +- `permissions-whitelist.template.json` files are **reference/documentation + only** — the actual rules are generated and written by each plugin's + `scripts/setup.sh`, not read from the template at runtime. +- git-manager's wrapper deliberately rejects `stash`, `merge`, `rebase`, + `reset`, and arbitrary `git config` — these can rewrite/discard + history or working-tree state irreversibly. Raw `git` remains a valid, + visible fallback for those (nudged, not blocked, by + `force-ask-on-raw-git.sh` if that hook is installed).