Add CLAUDE.md documenting repo architecture and conventions
This commit is contained in:
@@ -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 <name>`) 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 `<workspace>/repo/` with a sibling
|
||||||
|
`<workspace>/.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 `<workspace>`, 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 <workspace>/repo ...` or
|
||||||
|
`cd <workspace>/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/<name>/ # canonical, tool-neutral — SKILL.md, scripts/, references/
|
||||||
|
└── vendor/claude-code/plugins/<name>/ # Claude Code-specific adapter
|
||||||
|
├── .claude-plugin/plugin.json
|
||||||
|
├── skills/<name> -> ../../../../../skills/<name> (symlink, not a copy)
|
||||||
|
├── commands/setup.md # -> /<name>:setup
|
||||||
|
├── permissions-whitelist.template.json
|
||||||
|
└── hooks/ # git-manager only, currently
|
||||||
|
```
|
||||||
|
|
||||||
|
- `skills/<name>/` is the *only* place skill content lives. It assumes
|
||||||
|
nothing about the host tool: config is read from
|
||||||
|
`~/.agent-skills/<name>/config.json`, never a Claude-specific path, so the
|
||||||
|
same `SKILL.md` works unmodified in other Agent-Skills-compatible tools.
|
||||||
|
- `vendor/claude-code/plugins/<name>/` holds everything Claude Code-specific:
|
||||||
|
plugin manifest, `Bash(...)` permission whitelist, the `/setup` slash
|
||||||
|
command, and (for git-manager) `PreToolUse` hooks. Its `skills/<name>` 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/<tool>/`
|
||||||
|
tree symlinked back to the same `skills/<name>/`, 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/<name>/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/<name>/bin/`, never Claude Code's
|
||||||
|
internal plugin cache path (`~/.claude/plugins/cache/.../<version>/`),
|
||||||
|
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/<new-name>/` with `SKILL.md` (+ `scripts/`/`references/` as
|
||||||
|
needed). Config path: `~/.agent-skills/<new-name>/config.json`.
|
||||||
|
2. `vendor/claude-code/plugins/<new-name>/` with `.claude-plugin/plugin.json`,
|
||||||
|
a `skills/<new-name>` 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/<name> -> ../../../../../skills/<name>`)
|
||||||
|
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).
|
||||||
Reference in New Issue
Block a user